Slivers help you create smooth scrolling effects with flexible layouts in Flutter. They let you build lists, grids, and app bars that can change size or behavior as you scroll.
Slivers (SliverList, SliverGrid, SliverAppBar) in Flutter
class MySliverWidget extends StatelessWidget { @override Widget build(BuildContext context) { return CustomScrollView( slivers: [ SliverAppBar( title: Text('Title'), expandedHeight: 200, flexibleSpace: FlexibleSpaceBar( background: Image.asset('path/to/image.jpg', fit: BoxFit.cover), ), pinned: true, ), SliverList( delegate: SliverChildBuilderDelegate( (context, index) => ListTile(title: Text('Item $index')), childCount: 10, ), ), SliverGrid( delegate: SliverChildBuilderDelegate( (context, index) => Container(color: Colors.blue, child: Center(child: Text('Grid $index'))), childCount: 6, ), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), ), ], ); } }
SliverAppBar creates a flexible app bar that can expand and collapse.
SliverList builds a scrollable list of widgets lazily.
SliverGrid builds a scrollable grid of widgets lazily.
SliverAppBar( title: Text('My AppBar'), pinned: true, expandedHeight: 150, flexibleSpace: FlexibleSpaceBar( background: Image.network('https://example.com/image.jpg', fit: BoxFit.cover), ), )
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text('Item $index')),
childCount: 0,
),
)SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, index) => Container(color: Colors.red, child: Text('Grid $index')),
childCount: 1,
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 1),
)SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text('First Item')),
childCount: 1,
),
)This app shows a scrollable screen with a flexible app bar at the top. The app bar has a Flutter logo that expands and shrinks as you scroll. Below it is a list of 5 items, followed by a grid of 4 colored items arranged in 2 columns.
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: CustomScrollView( slivers: [ SliverAppBar( title: const Text('Sliver Demo'), expandedHeight: 150, flexibleSpace: const FlexibleSpaceBar( background: FlutterLogo(size: 200), ), pinned: true, ), SliverList( delegate: SliverChildBuilderDelegate( (context, index) => ListTile(title: Text('List Item $index')), childCount: 5, ), ), SliverGrid( delegate: SliverChildBuilderDelegate( (context, index) => Container( color: index.isEven ? Colors.blue : Colors.green, child: Center(child: Text('Grid Item $index', style: const TextStyle(color: Colors.white))), ), childCount: 4, ), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2), ), ], ), ), ); } }
Time complexity: Slivers load items lazily, so scrolling is efficient even with many items.
Space complexity: Only visible items are kept in memory, saving space.
Common mistake: Forgetting to use CustomScrollView to hold slivers causes errors.
Use SliverList for vertical lists and SliverGrid for grids inside scroll views.
SliverAppBar is great for flexible headers that react to scrolling.
Slivers let you build scrollable areas with flexible headers, lists, and grids.
Use SliverAppBar for a header that expands and pins on scroll.
Use SliverList and SliverGrid to build lazy-loading lists and grids inside CustomScrollView.
Practice
SliverAppBar in a Flutter app?Solution
Step 1: Understand
SliverAppBarroleSliverAppBaris designed to create headers that can expand and collapse as the user scrolls.Step 2: Compare options with
Only To create a header that can expand, collapse, and stay visible when scrolling describes the expandable and pinned header behavior ofSliverAppBarbehaviorSliverAppBar.Final Answer:
To create a header that can expand, collapse, and stay visible when scrolling -> Option DQuick Check:
SliverAppBar= expandable header [OK]
- Confusing SliverAppBar with fixed AppBar
- Thinking SliverAppBar creates grids or lists
- Assuming SliverAppBar is a footer widget
SliverList inside a CustomScrollView?Solution
Step 1: Recall
SliverListconstructorSliverListrequires adelegateparameter, usuallySliverChildBuilderDelegateorSliverChildListDelegate.Step 2: Check each option's syntax
SliverList(delegate: SliverChildBuilderDelegate((context, index) => Text('Item $index')))correctly usesdelegate: SliverChildBuilderDelegate. Options A, B, and C use invalid parameters or properties.Final Answer:
SliverList(delegate: SliverChildBuilderDelegate((context, index) => Text('Item $index'))) -> Option BQuick Check:
SliverList needs delegate =SliverList(delegate: SliverChildBuilderDelegate((context, index) => Text('Item $index')))[OK]
- Using children instead of delegate
- Using itemBuilder directly on SliverList
- Passing items instead of delegate
CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 100,
pinned: true,
flexibleSpace: FlexibleSpaceBar(title: Text('Hello')),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(title: Text('Item $index')),
childCount: 3,
),
),
],
)Solution
Step 1: Analyze
The app bar is pinned and has a flexible space with title 'Hello', so it stays visible when scrolling.SliverAppBarpropertiesStep 2: Analyze
The list builds 3 items labeled 'Item 0', 'Item 1', and 'Item 2'.SliverListdelegateFinal Answer:
A scrollable view with a pinned app bar titled 'Hello' and 3 list items labeled Item 0 to Item 2 -> Option AQuick Check:
Pinned SliverAppBar + SliverList with 3 items = A scrollable view with a pinned app bar titled 'Hello' and 3 list items labeled Item 0 to Item 2 [OK]
- Thinking pinned means static, not scrollable
- Confusing list items count or labels
- Assuming SliverAppBar cannot be pinned
CustomScrollView(
slivers: [
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
children: List.generate(4, (index) => Container(color: Colors.blue)),
),
],
)Solution
Step 1: Check
SliverGridconstructor requirementsSliverGridrequires adelegateparameter, notchildren.Step 2: Validate other parts
SliverGridDelegateWithFixedCrossAxisCountis valid, andList.generatecan be used inside a delegate.Final Answer:
SliverGrid requires a delegate, not a children parameter -> Option CQuick Check:
SliverGrid needs delegate, not children [OK]
- Using children instead of delegate in SliverGrid
- Confusing SliverGridDelegateWithFixedCrossAxisCount as invalid
- Thinking CustomScrollView disallows SliverGrid
Solution
Step 1: Identify correct widget for scrollable slivers
CustomScrollViewwithsliversparameter is needed to combineSliverAppBar,SliverGrid, andSliverList.Step 2: Check each option's structure
CustomScrollView(slivers: [SliverAppBar(pinned: true, expandedHeight: 200, flexibleSpace: FlexibleSpaceBar(title: Text('Gallery'))), SliverGrid(delegate: SliverChildBuilderDelegate((c, i) => Image.network(urls[i]), childCount: urls.length), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3)), SliverList(delegate: SliverChildBuilderDelegate((c, i) => ListTile(title: Text(items[i])), childCount: items.length))])correctly usesCustomScrollViewwith slivers and proper delegates.ListView(children: [AppBar(title: Text('Gallery')), GridView.count(crossAxisCount: 3, children: images), ListView(children: texts)])uses nested scrollables incorrectly.CustomScrollView(children: [SliverAppBar(), SliverGrid(), SliverList()])useschildreninstead ofslivers.Column(children: [SliverAppBar(), SliverGrid(), SliverList()])usesColumnwhich cannot host slivers.Final Answer:
CustomScrollView with SliverAppBar, SliverGrid, and SliverList using delegates -> Option AQuick Check:
Use CustomScrollView with slivers and delegates =CustomScrollView(slivers: [SliverAppBar(pinned: true, expandedHeight: 200, flexibleSpace: FlexibleSpaceBar(title: Text('Gallery'))), SliverGrid(delegate: SliverChildBuilderDelegate((c, i) => Image.network(urls[i]), childCount: urls.length), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3)), SliverList(delegate: SliverChildBuilderDelegate((c, i) => ListTile(title: Text(items[i])), childCount: items.length))])[OK]
- Using ListView or Column instead of CustomScrollView for slivers
- Passing slivers as children instead of slivers parameter
- Not using delegates for SliverGrid and SliverList
Ready to prove it?
Pass the test and this pattern moves unknown
