Collapsing headers, mixed lists and grids, and sticky sections all require slivers.
A sliver is a piece of a scrollable area that lays itself out lazily according to the scroll position. ListView and GridView are convenience wrappers around a single sliver. To mix several kinds of content in one scroll, use a `CustomScrollView` with a list of slivers:
- `SliverAppBar` — an app bar that can expand, collapse (
expandedHeight,flexibleSpace: FlexibleSpaceBar(...)), staypinned, or reappear when scrolling up (floating,snap). - `SliverList` with
SliverChildBuilderDelegate, or the convenientSliverList.builder/SliverList.separated— lazy lists. - `SliverGrid` — lazy grids.
- `SliverToBoxAdapter` — wraps one ordinary (box) widget.
- `SliverPadding`, `SliverFillRemaining`, `SliverPersistentHeader` (custom sticky headers), and
PinnedHeaderSliver/SliverResizingHeaderin recent Flutter versions.
Only sliver widgets may be direct children of slivers:; putting a plain widget there throws. Box widgets go inside SliverToBoxAdapter, and large lists must stay as SliverList to remain lazy — never a Column in an adapter.
Slivers use `SliverConstraints` (scroll offset, remaining paint extent) instead of box constraints, and report a SliverGeometry. That's what lets them shrink, pin or disappear as you scroll.
NestedScrollView coordinates an outer header with inner scrollables, for example tabs under a collapsing app bar.
Example
import 'package:flutter/material.dart';
class ArticleScreen extends StatelessWidget {
const ArticleScreen({super.key});
@override
Widget build(BuildContext context) => Scaffold(
body: CustomScrollView(slivers: [
const SliverAppBar(
pinned: true,
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(title: Text('Flutter Weekly')),
),
const SliverToBoxAdapter(
child: Padding(padding: EdgeInsets.all(16), child: Text('Top picks')),
),
SliverGrid.count(crossAxisCount: 3, children: [
for (var i = 0; i < 6; i++) Card(child: Center(child: Text('Pick $i'))),
]),
SliverList.builder( // lazy, any length
itemCount: 50,
itemBuilder: (context, i) => ListTile(title: Text('Story #$i')),
),
]),
);
}Remember
- CustomScrollView combines several slivers in one scroll
- SliverAppBar gives collapsing, pinned and floating headers
- Only slivers go in
slivers:; wrap box widgets in SliverToBoxAdapter
Watch out for
- Putting a big Column of items in a SliverToBoxAdapter, losing lazy building.