pub struct ScrollController { /* private fields */ }Expand description
A cloneable handle onto a ScrollView or a
ListView: drive it with jump_to/
animate_to (and, on a keyed list,
scroll_to_item), read where it stands with
offset/max_offset/
viewport_extent, and observe it with
on_change. Every clone shares one state, so the handle
an app keeps in its state and the one attached to the view are the same.
See the module docs for the apply/publish contract.
use frust_widgets::{ScrollController, ScrollView, scroll_view, text};
let controller = ScrollController::new();
let view: ScrollView<()> = scroll_view(text("hi")).controller(controller.clone());
controller.jump_to(120.0); // applied at the view's next layout or paintImplementations§
Source§impl ScrollController
impl ScrollController
Sourcepub fn new() -> Self
pub fn new() -> Self
A controller attached to nothing yet, reading offset, extent and
viewport 0.0.
Sourcepub fn jump_to(&self, offset: f64)
pub fn jump_to(&self, offset: f64)
Scroll to offset (px scrolled down) at once.
Applied by the attached surface at the start of its next layout or
paint, clamped to [0, max_offset] against that pass’s extent; it stops
any fling, release-settle or ballistic simulation in flight. NaN is
ignored; f64::INFINITY lands on the bottom edge. Issued while nothing
is attached (or before the attached surface has laid out), it waits for
the first layout of the next surface to attach.
Sourcepub fn animate_to(&self, offset: f64, options: AnimateTo)
pub fn animate_to(&self, offset: f64, options: AnimateTo)
Ease to offset over options.duration_ms/options.curve, clamped
to [0, max_offset].
Applied — like ScrollController::jump_to — at the attached
surface’s next layout or paint, and runs through the same ballistic
driver a release fling does, so paint cadence, request_frame and the
installed physics’ boundary handling are shared rather than
duplicated. A later jump_to/animate_to recorded before this one
finishes replaces it outright (drained in recording order, so the
later command’s own reset always runs after this one’s). Any user
pointer Down or wheel input on the surface cancels it too, leaving
the surface wherever it had eased to — user input always wins. The
app’s motion.reduce_motion theme flag collapses this to an instant
jump. NaN is ignored.
Sourcepub fn scroll_to_item(
&self,
key: impl Into<ChildKey>,
alignment: ItemAlignment,
animated: bool,
)
pub fn scroll_to_item( &self, key: impl Into<ChildKey>, alignment: ItemAlignment, animated: bool, )
Scroll a keyed ListView so the row whose key is
key lands at alignment in the viewport — jumping there, or easing
there when animated is true.
key is the same identity the list’s
builder_keyed key_of returns for
the row (anything that converts into a ChildKey: an id, a name, a
ChildKey itself). Applied like ScrollController::jump_to — at the
attached list’s next rebuild, layout or paint, replacing any jump or
animation in flight — and resolved then against the list’s current
data:
- Resolution is O(item count) at worst. The list keeps no
key-to-index map beyond its materialized window, so a key outside the
window is found by calling
key_ofover the items in order. One scan per request (and per settle frame for a row that left the window), never per frame. - Estimated, then corrected. In variable-extent mode
(
ListView::estimated_item_extent) the row’s position is computed from the heights measured so far and the estimate for every row not yet laid out. Once the jump lands (or the animation finishes), each following layout measures the rows now on screen, re-resolves the row’s aligned position and corrects to it, for at most a few frames (the list’s own docs state the bound) — so the row ends aligned even when the rows ahead of it were never measured. A userDown, wheel orCancelends the request at once. - An unknown key is a no-op. A key no row carries — or any key on a
positional
ListView::builderlist, which has no keys — leaves the list where it is and reports itself only through a debug-build log, since a recorded command has no caller left to return aResultto. - Lists only. A
ScrollViewholding this handle ignores the request (debug-build log); its offset commands are unaffected.
animated eases through the same tween ScrollController::animate_to
runs, timed from the theme’s motion tokens (motion.durations.slow and
motion.easing.spatial, the neutral scheme’s values when no theme is
threaded); the theme’s motion.reduce_motion flag collapses it to a
jump.
Sourcepub fn is_animating(&self) -> bool
pub fn is_animating(&self) -> bool
Whether the currently attached surface is running an
animate_to tween — false once it completes, is
replaced by a later jump/animate, or is interrupted by user input;
false before any surface has ever started one; and false once the
surface that was running one is dropped, taken over, or rebinds to a
different handle (see the module docs for the reconciliation
that guarantees this).
Sourcepub fn offset(&self) -> f64
pub fn offset(&self) -> f64
The clamped offset the attached surface last published (0.0 until a
surface attaches and lays out; the last published value after it
detaches).
Sourcepub fn max_offset(&self) -> f64
pub fn max_offset(&self) -> f64
The maximum offset (content − viewport, never negative) the attached
surface last published.
Sourcepub fn viewport_extent(&self) -> f64
pub fn viewport_extent(&self) -> f64
The attached surface’s last laid-out extent along the scroll axis (its
height, for the vertical ScrollView).
Sourcepub fn is_attached(&self) -> bool
pub fn is_attached(&self) -> bool
Whether a surface currently holds this handle.
Sourcepub fn on_change<F: Fn(ScrollInfo) + 'static>(
&self,
listener: F,
) -> ScrollSubscription
pub fn on_change<F: Fn(ScrollInfo) + 'static>( &self, listener: F, ) -> ScrollSubscription
Call listener with every ScrollInfo the attached surface
publishes that differs from the previous one — user drag, wheel,
fling/settle frames, relayout and applied jumps alike.
The listener runs with no &mut State (it may fire during layout or
paint), so it reacts by writing a signal or recording into the handle,
never by mutating app state directly. It stays subscribed for as long
as the returned ScrollSubscription lives.