Skip to main content

virtual_list

Function virtual_list 

Source
pub fn virtual_list<E: IntoElement>(
    count: impl Fn() -> usize + 'static,
    row_height: f32,
    row: impl Fn(usize) -> E + 'static,
) -> Element<ScrollView>
Expand description

Creates a list of count rows of one height inside a scroll view, with only the rows near the viewport mounted.

The returned element is the scroll view; give it a height, either directly or through a parent that sizes it. It scrolls with the wheel like any scroll view, and it shows a thumb for the whole list, because its content is a spacer panel as tall as count rows, whatever the mounted window is.

The rows are built by row, which receives the row’s index. A row is built once, the first time its index enters the window, and it stays mounted, with its reactive state, until the window moves past it. Content that changes while a row stays mounted must come from the signals that row reads: a new value for an index that never left the window reaches no mounted row. The row should keep to row_height; a taller one overlaps the row below it, and a shorter one leaves the spacer’s background showing.

count runs inside a binding, so only the signals it reads remount the window. A shrinking count clamps the offset, and the window follows on the frame after the new height has been measured.

The list owns its scroll offset; do not call ScrollExt::offset on the returned view, because the window would follow the signal the list started with while the view scrolls by the one the call installs.

row_height must be positive and finite. Anything else mounts no rows, and a list built that way shows an empty view.

use smudge_core::reactive::{RwSignal, prelude::*};
use smudge_core::style::px;
use smudge_text::label;
use smudge_widgets::virtual_list;

let count = RwSignal::new(100_000);
let list = virtual_list(
    move || count.get(),
    24.0,
    |index| label(format!("Row {index}")),
)
.height(px(480.0));