Slivers & Scrolling
Lazy building is the whole point
Section titled “Lazy building is the whole point”A scrollable list might contain ten thousand items, but the screen shows twenty. Building all ten thousand would be catastrophic. The key idea of Flutter scrolling is lazy building: only the items near the visible area are built, and they are recycled as you scroll.
This is why the constructor you choose matters enormously:
// ❌ Builds ALL children up front — fine for a few, fatal for thousands.ListView(children: [ for (final item in items) Tile(item) ])
// ✅ Builds children on demand as they scroll into view.ListView.builder( itemCount: items.length, itemBuilder: (context, i) => Tile(items[i]),)ListView.builder (and GridView.builder) call itemBuilder only for items the viewport needs. For any list that could be long, always use the builder form.
The viewport and slivers
Section titled “The viewport and slivers”Under a scrollable is a viewport — the window you see — and inside it, slivers. A sliver is a scrollable region that knows how to lay itself out lazily against the viewport. ListView is a convenience that wraps a single sliver; when you need more than one scroll effect in one scroll view, you compose slivers yourself.
flowchart TB scroll["CustomScrollView"] --> vp["Viewport (visible window)"] vp --> s1["SliverAppBar (collapses on scroll)"] vp --> s2["SliverList (builds only visible tiles)"] vp --> offscreen["off-screen tiles: not built yet"]
CustomScrollView: composing scroll effects
Section titled “CustomScrollView: composing scroll effects”CustomScrollView takes a list of slivers and scrolls them as one. This is how you build a collapsing header above a list, or a grid and a list in the same scroll view.
CustomScrollView( slivers: [ const SliverAppBar( floating: true, expandedHeight: 200, // a header that collapses as you scroll ), SliverList( delegate: SliverChildBuilderDelegate( (context, i) => Tile(items[i]), // still lazy childCount: items.length, ), ), ],)The mental model: a normal widget occupies a fixed box; a sliver occupies a scrollable extent and negotiates with the viewport about how much of it is visible. SliverAppBar, SliverList, SliverGrid, and SliverToBoxAdapter (to drop a regular widget into a sliver list) are the pieces you compose.
Common scrolling pitfalls
Section titled “Common scrolling pitfalls”- Nesting scrollables the same direction (a
ListViewinside aListView) fights over the scroll and throws unbounded-constraint errors — use slivers orshrinkWrapdeliberately. shrinkWrap: truemakes a list size to its content instead of the viewport, but it builds everything and loses laziness — use it only for genuinely small lists.- Missing keys on reorderable lists cause the wrong state to attach to the wrong item (see the Keys lesson).