pub struct ListState(/* private fields */);Expand description
The state of a list. Store it on your view and pass a clone to list each frame.
The state records each row’s height, the scroll position and the follow mode. Call its
methods when the rows change, such as Self::splice or Self::remeasure_items.
Clones share the same state.
Implementations§
Source§impl ListState
impl ListState
Sourcepub fn new(
item_count: usize,
alignment: ListAlignment,
overdraw: Pixels,
) -> Self
pub fn new( item_count: usize, alignment: ListAlignment, overdraw: Pixels, ) -> Self
Creates the state for a list of item_count rows, to store on your view.
alignment sets where the list starts: ListAlignment::Top at the first row, or
ListAlignment::Bottom at the last row, as a chat log does.
overdraw is extra space above and below the viewport. Rows in that space are rendered and
measured, but not painted, so rows that scroll into view are already measured.
Rows start unmeasured. An unmeasured row counts as zero pixels tall until it is rendered,
unless it has a height hint from Self::with_uniform_item_height.
§Examples
let state = ListState::new(3, ListAlignment::Top, px(100.));
assert_eq!(state.item_count(), 3);Sourcepub fn measure_all(self) -> Self
pub fn measure_all(self) -> Self
Measures every row on the next layout, instead of only the rows that are rendered.
The scrollbar then reflects the full content height from the first frame. The cost is one
render and measure per row, which is slow for a large list. For rows of similar height,
Self::with_uniform_item_height gives a close estimate without measuring. Measuring runs
again after the width changes, and after Self::reset, Self::remeasure or
Self::remeasure_items.
Sourcepub fn with_uniform_item_height(self, height: Pixels) -> Self
pub fn with_uniform_item_height(self, height: Pixels) -> Self
Gives every unmeasured row a height estimate of height, so the scrollbar is the right
size before the rows are rendered.
Each row’s real height replaces the estimate when the row is rendered. This costs less than
Self::measure_all, and suits lists whose rows are close to one height, such as table rows.
§Examples
let state = ListState::new(1_000, ListAlignment::Top, px(0.)).with_uniform_item_height(px(50.));
assert_eq!(state.max_offset_for_scrollbar().y, px(50_000.));Sourcepub fn reset(&self, element_count: usize)
pub fn reset(&self, element_count: usize)
Replaces every row with element_count new, unmeasured rows, and returns the scroll
position to the start.
The position goes to the first row for ListAlignment::Top and to the last row for
ListAlignment::Bottom. Scroll events are dropped until the next paint. To keep the scroll
position, use Self::splice.
§Examples
let state = ListState::new(3, ListAlignment::Top, px(0.));
state.reset(10);
assert_eq!(state.item_count(), 10);
assert_eq!(state.logical_scroll_top().item_ix, 0);Sourcepub fn reset_with_uniform_height(&self, element_count: usize, height: Pixels)
pub fn reset_with_uniform_height(&self, element_count: usize, height: Pixels)
Like Self::reset, and gives every new row the height estimate height.
Sourcepub fn remeasure(&self)
pub fn remeasure(&self)
Marks every row unmeasured, so each is measured again when next rendered.
Use this when all rows change height together, such as when the font size changes. The
scroll position keeps the same fraction of the row at the top of the viewport. For one row
whose content changed, use Self::remeasure_items.
Sourcepub fn remeasure_items(&self, range: Range<usize>)
pub fn remeasure_items(&self, range: Range<usize>)
Marks the rows in range unmeasured, so they are measured again when next rendered.
Use this when a row’s content changed height but the row is still at the same index, such as
streaming text. The scroll position is kept. If the row at the top of the viewport is in
range, the same pixel offset into that row is kept. Unlike Self::splice, the row count
doesn’t change.
Sourcepub fn item_count(&self) -> usize
pub fn item_count(&self) -> usize
Returns the number of rows in this list.
§Examples
let state = ListState::new(3, ListAlignment::Top, px(0.));
assert_eq!(state.item_count(), 3);Sourcepub fn is_scrolled_to_end(&self) -> Option<bool>
pub fn is_scrolled_to_end(&self) -> Option<bool>
Returns whether the list is scrolled to its end.
Returns None when the list isn’t scrollable, when it hasn’t been painted yet, or when a row
has no height yet, because the end isn’t known until then. A row has a height once it is
rendered, or once it has a height hint from Self::with_uniform_item_height.
§Examples
let state = ListState::new(3, ListAlignment::Top, px(0.));
assert_eq!(state.is_scrolled_to_end(), None);Sourcepub fn splice(&self, old_range: Range<usize>, count: usize)
pub fn splice(&self, old_range: Range<usize>, count: usize)
Replaces the rows in old_range with count new, unmeasured rows.
Call this after you add, remove or move rows. Rows after old_range keep their measurements
and shift by the change in count. New rows count as zero pixels tall until they are rendered.
If the row at the top of the viewport is in old_range, the list scrolls to the start of the
new rows. Use Self::splice_focusable to keep a focused row rendered.
splice(old_count..old_count, 1) appends one row, and splice(0..0, 1) inserts one at the top.
§Examples
let state = ListState::new(3, ListAlignment::Top, px(0.));
state.splice(1..2, 4); // replace the middle row with four new rows
assert_eq!(state.item_count(), 6);Sourcepub fn splice_focusable(
&self,
old_range: Range<usize>,
focus_handles: impl IntoIterator<Item = Option<FocusHandle>>,
)
pub fn splice_focusable( &self, old_range: Range<usize>, focus_handles: impl IntoIterator<Item = Option<FocusHandle>>, )
Replaces the rows in old_range like Self::splice, and gives each new row an optional focus handle.
Pass None for rows that can’t take focus. If a row with a focus handle holds focus when it
scrolls out of view, the list keeps rendering it after the visible rows, so keyboard input
still reaches it, until focus moves elsewhere.
Sourcepub fn set_scroll_handler(
&self,
handler: impl FnMut(&ListScrollEvent, &mut Window, &mut App) + 'static,
)
pub fn set_scroll_handler( &self, handler: impl FnMut(&ListScrollEvent, &mut Window, &mut App) + 'static, )
Sets a callback that runs after each wheel or trackpad scroll of the list.
The callback runs on every wheel event the list handles, including events that don’t move it.
It does not run for Self::scroll_to, Self::scroll_by, Self::scroll_to_reveal_item
or scrollbar drags.
The callback runs while the list’s state is borrowed. Use the ListScrollEvent it receives,
and don’t call methods on the ListState from inside it.
§Examples
let scrolls = Rc::new(Cell::new(0));
let counted = scrolls.clone();
window.update(|feed, _, _| {
feed.state.set_scroll_handler(move |event, _window, _cx| {
assert_eq!(event.count, 10);
counted.set(counted.get() + 1);
});
});
window.draw();
// Scroll down 100px, which is row 2 of 50px rows.
window.simulate_scroll(point(px(20.), px(20.)), point(px(0.), px(-100.)));
assert_eq!(scrolls.get(), 1);
window.read(|feed, _| assert_eq!(feed.state.logical_scroll_top().item_ix, 2));Sourcepub fn logical_scroll_top(&self) -> ListOffset
pub fn logical_scroll_top(&self) -> ListOffset
Returns the first visible row, and the pixel offset into that row.
Before the list is scrolled, this is row 0 for ListAlignment::Top. For
ListAlignment::Bottom it is the end of the list, the item count, with an offset of zero.
Pass a value you saved to Self::scroll_to to restore a position.
Sourcepub fn scroll_by(&self, distance: Pixels)
pub fn scroll_by(&self, distance: Pixels)
Scrolls the list by distance pixels: toward the end when positive, and toward the start when negative.
The start is clamped at zero. Past the end, the next paint clamps the position. A scroll
toward the start stops following the tail. This doesn’t call the scroll handler, and it
doesn’t redraw, so call cx.notify() to show the new position.
§Examples
window.draw();
window.update(|feed, _, cx| {
feed.state.scroll_by(px(120.));
cx.notify();
});
window.draw();
// 120px down is row 2, 20px into it.
window.read(|feed, _| {
let top = feed.state.logical_scroll_top();
assert_eq!((top.item_ix, top.offset_in_item), (2, px(20.)));
});Sourcepub fn scroll_to_end(&self)
pub fn scroll_to_end(&self)
Scrolls past the last row, so the bottom of the list stays in view while the last row grows.
Unlike Self::scroll_to_reveal_item, this anchors to the end of the list, not to a row. The
next paint walks back from the end and shows the bottom of the last row, even while that row
is still growing, as when text streams in. The scroll takes effect on the next paint.
Sourcepub fn set_follow_mode(&self, mode: FollowMode)
pub fn set_follow_mode(&self, mode: FollowMode)
Sets whether the list keeps the end in view as rows are added.
FollowMode::Tail scrolls to the end now, and keeps it there on each paint while
Self::is_following_tail is true. A user scroll toward the start stops following, and the
list starts following again when the user scrolls back to the end. FollowMode::Normal
stops following and leaves the position where it is.
§Examples
let state = ListState::new(5, ListAlignment::Top, px(0.));
state.set_follow_mode(FollowMode::Tail);
assert!(state.is_following_tail());
state.set_follow_mode(FollowMode::Normal);
assert!(!state.is_following_tail());Sourcepub fn pause_following_tail(&self)
pub fn pause_following_tail(&self)
Stops following the tail and keeps the current position, until the user scrolls back to the end.
Unlike Self::set_follow_mode with FollowMode::Normal, the list stays in
FollowMode::Tail, so it resumes following when the view returns to the end. Does nothing
if the list isn’t following.
Use this when something other than the user changes a row’s height, such as zooming a diagram, and the position should not jump to the end.
§Examples
let state = ListState::new(5, ListAlignment::Top, px(0.));
state.set_follow_mode(FollowMode::Tail);
state.pause_following_tail();
assert!(!state.is_following_tail());Sourcepub fn is_following_tail(&self) -> bool
pub fn is_following_tail(&self) -> bool
Returns whether the list is following the tail right now.
This is true after Self::set_follow_mode with FollowMode::Tail, until the user scrolls
toward the start or Self::pause_following_tail is called. It is false in
FollowMode::Normal.
Sourcepub fn scroll_to(&self, scroll_top: ListOffset)
pub fn scroll_to(&self, scroll_top: ListOffset)
Scrolls the list so that scroll_top is at the top of the viewport.
If scroll_top is past the last row, the list scrolls to the end. A position before the end
stops following the tail.
§Examples
let state = ListState::new(5, ListAlignment::Top, px(0.));
state.scroll_to(ListOffset { item_ix: 2, offset_in_item: px(10.) });
assert_eq!(state.logical_scroll_top().item_ix, 2);
assert_eq!(state.logical_scroll_top().offset_in_item, px(10.));Sourcepub fn scroll_to_reveal_item(&self, ix: usize)
pub fn scroll_to_reveal_item(&self, ix: usize)
Scrolls the least amount that shows row ix fully.
A row above the current top is moved to the top of the viewport. A row below it is moved so its bottom edge sits at the bottom of the viewport. The position takes effect on the next paint.
§Examples
window.draw();
window.update(|feed, _, _| feed.state.scroll_to_reveal_item(9));
window.draw();
window.read(|feed, _| {
assert_eq!(feed.state.item_is_above_viewport(9), Some(false));
assert_eq!(feed.state.item_is_below_viewport(9), Some(false));
});Sourcepub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>>
pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>>
Returns the bounds of row ix in window coordinates, or None if the row is above the scroll
position or has not been measured.
A measured row below the viewport still has bounds, so compare them with
Self::viewport_bounds. Self::item_is_above_viewport and
Self::item_is_below_viewport answer that directly.
Sourcepub fn scrollbar_drag_started(&self)
pub fn scrollbar_drag_started(&self)
Tells the list that the user started dragging its scrollbar.
Until Self::scrollbar_drag_ended, the scrollbar uses the content height from this moment,
so the thumb doesn’t move while rows in the overdraw are measured.
Sourcepub fn scrollbar_drag_ended(&self)
pub fn scrollbar_drag_ended(&self)
Tells the list that the scrollbar drag has ended, so the scrollbar uses the live content
height again. See Self::scrollbar_drag_started.
Sourcepub fn is_scrollbar_dragging(&self) -> bool
pub fn is_scrollbar_dragging(&self) -> bool
Returns whether the scrollbar is being dragged.
This is true between Self::scrollbar_drag_started and Self::scrollbar_drag_ended.
Use it to tell a scrollbar drag from a wheel or trackpad scroll, for example to stop
auto-scrolling during a manual drag.
Sourcepub fn set_offset_from_scrollbar(&self, point: Point<Pixels>)
pub fn set_offset_from_scrollbar(&self, point: Point<Pixels>)
Scrolls the list to the position that a scrollbar reports.
point.y is a negative scroll offset, as Self::scroll_px_offset_for_scrollbar returns it.
It is clamped to the content. A drag to the end while the list is in FollowMode::Tail
resumes following the tail, and any other position stops it. Does nothing before the first paint.
Sourcepub fn max_offset_for_scrollbar(&self) -> Point<Pixels>
pub fn max_offset_for_scrollbar(&self) -> Point<Pixels>
Returns the largest scroll distance, as a positive y.
This is the content height minus the viewport height, using the heights measured so far and any height hints. During a scrollbar drag it keeps the value from when the drag started.
Sourcepub fn scroll_px_offset_for_scrollbar(&self) -> Point<Pixels>
pub fn scroll_px_offset_for_scrollbar(&self) -> Point<Pixels>
Returns the current scroll position for the scrollbar, as a negative y.
The value is the negation of how far the content has moved, so it is the negative of
Self::max_offset_for_scrollbar for a bottom-aligned list that is pinned to the end.
Sourcepub fn viewport_bounds(&self) -> Bounds<Pixels>
pub fn viewport_bounds(&self) -> Bounds<Pixels>
Returns the viewport’s bounds in window coordinates, from the last prepaint.
Before the first prepaint this returns empty bounds at the origin.
Sourcepub fn item_is_above_viewport(&self, ix: usize) -> Option<bool>
pub fn item_is_above_viewport(&self, ix: usize) -> Option<bool>
Returns whether row ix is entirely above the viewport, or None before the first layout.
Rows before the scroll position are above the viewport (Some(true)) even when they were
never measured. Any other row needs bounds, so it returns None if it hasn’t been measured.
A zero-height viewport still gives an answer, so the result doesn’t flicker while sibling UI
resizes the list.
Sourcepub fn item_is_below_viewport(&self, ix: usize) -> Option<bool>
pub fn item_is_below_viewport(&self, ix: usize) -> Option<bool>
Returns whether row ix is entirely below the viewport, or None when the answer isn’t known yet.
Rows before the scroll position return Some(false). Other rows follow the rules of
Self::item_is_above_viewport.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for ListState
impl !Send for ListState
impl !Sync for ListState
impl !UnwindSafe for ListState
impl Freeze for ListState
impl Unpin for ListState
impl UnsafeUnpin for ListState
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for Swhere
T: Real + Zero + Arithmetics + Clone,
Swp: WhitePoint<T>,
Dwp: WhitePoint<T>,
D: AdaptFrom<S, Swp, Dwp, T>,
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<T>,
replaced by palette::chromatic_adaptation::AdaptIntoUnclamped
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
replaced by palette::chromatic_adaptation::AdaptIntoUnclamped
Source§impl<T, C> AdaptIntoUnclamped<T> for Cwhere
T: AdaptFromUnclamped<C>,
impl<T, C> AdaptIntoUnclamped<T> for Cwhere
T: AdaptFromUnclamped<C>,
Source§type Scalar = <T as AdaptFromUnclamped<C>>::Scalar
type Scalar = <T as AdaptFromUnclamped<C>>::Scalar
Source§fn adapt_into_unclamped_with<M>(self) -> Twhere
M: LmsToXyz<<C as AdaptIntoUnclamped<T>>::Scalar> + XyzToLms<<C as AdaptIntoUnclamped<T>>::Scalar>,
fn adapt_into_unclamped_with<M>(self) -> Twhere
M: LmsToXyz<<C as AdaptIntoUnclamped<T>>::Scalar> + XyzToLms<<C as AdaptIntoUnclamped<T>>::Scalar>,
Source§impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
impl<T, C> ArraysFrom<C> for Twhere
C: IntoArrays<T>,
Source§fn arrays_from(colors: C) -> T
fn arrays_from(colors: C) -> T
Source§impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
impl<T, C> ArraysInto<C> for Twhere
C: FromArrays<T>,
Source§fn arrays_into(self) -> C
fn arrays_into(self) -> C
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
impl<WpParam, T, U> Cam16IntoUnclamped<WpParam, T> for Uwhere
T: FromCam16Unclamped<WpParam, U>,
Source§type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
type Scalar = <T as FromCam16Unclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn cam16_into_unclamped(
self,
parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>,
) -> T
fn cam16_into_unclamped( self, parameters: BakedParameters<WpParam, <U as Cam16IntoUnclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
impl<T, C> ComponentsFrom<C> for Twhere
C: IntoComponents<T>,
Source§fn components_from(colors: C) -> T
fn components_from(colors: C) -> T
Source§impl<T, C> ComponentsInto<C> for T
impl<T, C> ComponentsInto<C> for T
Source§fn components_into(self) -> C
fn components_into(self) -> C
Source§impl<T> FromAngle<T> for T
impl<T> FromAngle<T> for T
Source§fn from_angle(angle: T) -> T
fn from_angle(angle: T) -> T
angle.Source§impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
impl<T, U> FromStimulus<U> for Twhere
U: IntoStimulus<T>,
Source§fn from_stimulus(other: U) -> T
fn from_stimulus(other: U) -> T
other into Self, while performing the appropriate scaling,
rounding and clamping.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
impl<T, U> IntoAngle<U> for Twhere
U: FromAngle<T>,
Source§fn into_angle(self) -> U
fn into_angle(self) -> U
T.Source§impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
impl<WpParam, T, U> IntoCam16Unclamped<WpParam, T> for Uwhere
T: Cam16FromUnclamped<WpParam, U>,
Source§type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
type Scalar = <T as Cam16FromUnclamped<WpParam, U>>::Scalar
parameters when converting.Source§fn into_cam16_unclamped(
self,
parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>,
) -> T
fn into_cam16_unclamped( self, parameters: BakedParameters<WpParam, <U as IntoCam16Unclamped<WpParam, T>>::Scalar>, ) -> T
self into C, using the provided parameters.Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoStimulus<T> for T
impl<T> IntoStimulus<T> for T
Source§fn into_stimulus(self) -> T
fn into_stimulus(self) -> T
self into T, while performing the appropriate scaling,
rounding and clamping.Source§impl<T> Pointable for T
impl<T> Pointable for T
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
impl<T, C> TryComponentsInto<C> for Twhere
C: TryFromComponents<T>,
Source§type Error = <C as TryFromComponents<T>>::Error
type Error = <C as TryFromComponents<T>>::Error
try_into_colors fails to cast.Source§fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
fn try_components_into(self) -> Result<C, <T as TryComponentsInto<C>>::Error>
Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more