pub struct ListView<State>where
State: 'static,{ /* private fields */ }Expand description
A declarative, virtualized vertical list. See the module docs.
builder is a pure function of the item index; it is retained (an Rc) so
the previous frame’s view for a surviving index can be reconstructed during
reconciliation. All rows share the uniform, required item_extent.
Implementations§
Source§impl<State> ListView<State>where
State: 'static,
impl<State> ListView<State>where
State: 'static,
Sourcepub fn builder(
item_count: usize,
item_extent: f64,
builder: impl Fn(usize) -> AnyView<State> + 'static,
) -> ListView<State>
pub fn builder( item_count: usize, item_extent: f64, builder: impl Fn(usize) -> AnyView<State> + 'static, ) -> ListView<State>
Create a virtualized list of item_count rows, each item_extent
logical pixels tall, whose row at index is produced by builder.
The builder returns an AnyView (rows may differ in concrete view
type); spell each row with frust_core::any. Panics if
item_extent is not positive (the uniform extent is the virtualization
fast path; a zero/negative extent has no well-defined window).
§Contract
Rows are reconciled by raw item index, not by a stable key. This is
safe for append-only, truncate-only, and full-replace data, but a
mid-list insert/remove/reorder silently reattaches a retained row’s state
to different content at the same index. See the module docs’
Row identity section for the full rule, and
ListView::builder_keyed for the stable-key alternative that survives
a mid-list mutation.
Sourcepub fn builder_keyed(
item_count: usize,
item_extent: f64,
key_of: impl Fn(usize) -> ChildKey + 'static,
builder: impl Fn(usize) -> AnyView<State> + 'static,
) -> ListView<State>
pub fn builder_keyed( item_count: usize, item_extent: f64, key_of: impl Fn(usize) -> ChildKey + 'static, builder: impl Fn(usize) -> AnyView<State> + 'static, ) -> ListView<State>
Create a virtualized list whose rows are reconciled by the stable key
key_of(index) instead of by raw item index — the mid-list-mutation-safe
counterpart of ListView::builder, everything else identical.
key_of returns the identity of the row at an item index (a
ChildKey, built from any Hash value — an item id,
a name — via ChildKey::new/.into()); it is called once per
materialized slot per frame, never item_count times, and must be a
pure function of the index over one frame’s data, exactly like builder.
Panics if item_extent is not positive, like ListView::builder.
ListView::builder_keyed(
rows.len(),
56.0,
move |i| ChildKey::new(rows[i].id),
move |i| any::<AppState, _>(row_view(&rows[i])),
)§Contract
A row whose key stays in the window keeps its live widget — and so its
entire retained state — even when an insert/remove/reorder moves it to a
different index; a key that leaves the window (or the data) is torn down,
and a key entering is built fresh. Keys must be unique within a
window: a duplicate trips a debug_assert! and, in release, hands the
live row to the first slot claiming the key while later duplicates build
fresh (no panic, but which row keeps its state is arbitrary). See the
module docs’ Row identity section.
Sourcepub fn estimated_item_extent(self, estimate_px: f64) -> ListView<State>
pub fn estimated_item_extent(self, estimate_px: f64) -> ListView<State>
Let rows size themselves, taking estimate_px as the assumed extent of
every row that has not been measured yet — variable-extent mode,
available on ListView::builder_keyed lists only.
A materialized row is laid out under the list’s width with unbounded
height and reports whatever height it wants; that height is cached under
the row’s stable key and used from then on for window math, the scroll
extent, and the row’s content position. Unmeasured rows (everything not
yet laid out) count as estimate_px, so the scroll range converges on
the true content height as the user visits rows. The constructor’s
item_extent is unused in this mode — pass the same value as the
estimate for clarity.
ListView::builder_keyed(rows.len(), 72.0, key_of, builder)
.estimated_item_extent(72.0)§Contract
Keyed lists only. A measured extent is cached under row identity, so
it must move with the row; a positional list has no identity to cache
under. Calling this on a ListView::builder list trips a
debug_assert! and is inert in release — the list keeps its
closed-form uniform extent rather than panicking live (the same shape as
the duplicate-key tripwire, see the module docs’ Variable extents
section for why this is a debug_assert and not type-state). Panics if
estimate_px is not positive, like the constructors’ item_extent.
Sourcepub fn on_near_start<F>(self, callback: F, threshold_px: f64) -> ListView<State>where
F: Fn(&mut State) + 'static,
pub fn on_near_start<F>(self, callback: F, threshold_px: f64) -> ListView<State>where
F: Fn(&mut State) + 'static,
Fire callback when the scrolled window comes within threshold_px of
content start — the load-older edge for a newest-at-bottom chat list.
The callback is edge-triggered: it fires once per approach and rearms
only after the user scrolls away past 2 × threshold_px (or the item
count changes). Drag, wheel, and fling motion all observe it — fling
motion is driven at paint time (no frust_core::EventCtx), so a
fling-triggered fire is recorded and delivered on the next event, one
event late; a Cancel clears a pending fire without invoking the
callback.
Sourcepub fn on_near_end<F>(self, callback: F, threshold_px: f64) -> ListView<State>where
F: Fn(&mut State) + 'static,
pub fn on_near_end<F>(self, callback: F, threshold_px: f64) -> ListView<State>where
F: Fn(&mut State) + 'static,
Fire callback when the scrolled window comes within threshold_px of
content end — the load-newer edge for an infinite-scroll-downward
list.
Mirrors ListView::on_near_start exactly, measured from content end
instead of start: edge-triggered, firing once per approach and
rearming only after the user scrolls back past 2 × threshold_px away
from the end (or the item count changes). Drag, wheel, and fling motion
all observe it — a fling-triggered fire is recorded and delivered on the
next event, one event late; a Cancel clears a pending fire without
invoking the callback.
Sourcepub fn on_refresh_release<F>(self, callback: F) -> ListView<State>where
F: Fn(&mut State) + 'static,
pub fn on_refresh_release<F>(self, callback: F) -> ListView<State>where
F: Fn(&mut State) + 'static,
The pull-to-refresh trigger: fires on pointer Up when the list was
pulled past the top by more than REFRESH_TRIGGER_PX (post-resistance)
— the same name, signature, and threshold behavior as
crate::ScrollView::on_refresh_release, so a screen can swap between
the two containers without relearning the contract. Never fires on a
Cancel, and a bottom overscroll can never trigger it (only a past-top
pull can). See the module docs’ Overscroll and pull-to-refresh
section.
Sourcepub fn physics(self, physics: impl ScrollPhysics + 'static) -> ListView<State>
pub fn physics(self, physics: impl ScrollPhysics + 'static) -> ListView<State>
Install a custom ScrollPhysics strategy — the same seam
crate::ScrollView::physics installs, sharing scroll.rs’s
resistance/trigger/settle constants and this crate’s
crate::physics::parity/RubberBand
implementations.
use frust_widgets::{ListView, NeverScrollable, text};
let view: ListView<()> = ListView::builder(3, 40.0, |i| {
frust_core::any::<(), _>(text(i.to_string()))
})
.physics(NeverScrollable::new());§Build/rebuild semantics
Identical to crate::ScrollView::physics: a view built (or
rebuilt) with .physics(...) reinstalls it on the widget every
time; a view built (or rebuilt) without it leaves the widget’s
currently-installed physics untouched (a fresh build still starts at
crate::physics::default_physics, the widget’s own constructor
default).
Defaults to the platform-adaptive physics
(crate::physics::default_physics — Android clamping, elsewhere
bouncing) if never called; .physics(RubberBand::new()) is how an app
asks for the pre-seam rubber-band feel instead.
Sourcepub fn overscroll_effect(self, effect: OverscrollEffect) -> ListView<State>
pub fn overscroll_effect(self, effect: OverscrollEffect) -> ListView<State>
Select how past-edge pull is visualized. See OverscrollEffect
(crate::physics::effect) for the full contract — the same
selector crate::ScrollView::overscroll_effect installs.
use frust_widgets::{ListView, OverscrollEffect, text};
let view: ListView<()> = ListView::builder(3, 40.0, |i| {
frust_core::any::<(), _>(text(i.to_string()))
})
.overscroll_effect(OverscrollEffect::Stretch);Plain view-owned data, unlike ListView::physics: every
build/rebuild carries the current value down to
ListViewWidget::effect unconditionally.
Defaults to the effect paired with the platform’s default physics
(crate::physics::default_overscroll_effect): the M3E
OverscrollEffect::Stretch on Android, translate overscroll
(OverscrollEffect::Translate) everywhere else.
impl<State> ListView<State>where
State: 'static,
The reconciliation half of View::rebuild, split per identity mode. See the
module docs’ Row identity section for which one runs when.
Trait Implementations§
Source§impl<State> View<State> for ListView<State>where
State: 'static,
impl<State> View<State> for ListView<State>where
State: 'static,
Source§type Element = ListViewWidget
type Element = ListViewWidget
Source§fn build(&self, ctx: &mut BuildCtx<'_>) -> ListViewWidget
fn build(&self, ctx: &mut BuildCtx<'_>) -> ListViewWidget
Source§fn rebuild(
&self,
prev: &ListView<State>,
element: &mut ListViewWidget,
ctx: &mut BuildCtx<'_>,
) -> ChangeFlags
fn rebuild( &self, prev: &ListView<State>, element: &mut ListViewWidget, ctx: &mut BuildCtx<'_>, ) -> ChangeFlags
prev (the previous view of the same type) against the live
element, mutating it in place and reporting what changed.Auto Trait Implementations§
impl<State> !RefUnwindSafe for ListView<State>
impl<State> !Send for ListView<State>
impl<State> !Sync for ListView<State>
impl<State> !UnwindSafe for ListView<State>
impl<State> Freeze for ListView<State>
impl<State> Unpin for ListView<State>
impl<State> UnsafeUnpin for ListView<State>where
Rc<dyn Fn(usize) -> AnyView<State>>: UnsafeUnpin,
Option<Rc<dyn Fn(&mut State)>>: UnsafeUnpin,
Blanket Implementations§
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.