Mastering Flutter Slivers for Custom Scroll Effects
Mastering Flutter Slivers for Custom Scroll Effects
What You’ll Learn
Slivers are the building blocks of scrollable areas in Flutter. Understanding them unlocks powerful custom scroll effects like collapsing headers, parallax effects, and mixed-content scrolling that would be complex to achieve otherwise.
Example
Here’s a practical example with a collapsing app bar and a grid of items:
import 'package:flutter/material.dart';
class SliverDemoScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
// Collapsing header
SliverAppBar(
expandedHeight: 200,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: Text('My Gallery'),
background: Image.network(
'https://picsum.photos/800/400',
fit: BoxFit.cover,
),
),
),
// Sticky header
SliverPersistentHeader(
pinned: true,
delegate: _StickyHeaderDelegate(
child: Container(
color: Colors.blue,
padding: EdgeInsets.all(16),
child: Text('Photos', style: TextStyle(color: Colors.white)),
),
),
),
// Grid of items
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
),
delegate: SliverChildBuilderDelegate(
(context, index) => Card(
child: Center(child: Text('Item $index')),
),
childCount: 20,
),
),
],
),
);
}
}
class _StickyHeaderDelegate extends SliverPersistentHeaderDelegate {
final Widget child;
_StickyHeaderDelegate({required this.child});
@override
Widget build(context, shrinkOffset, overlapsContent) => child;
@override
double get maxExtent => 50;
@override
double get minExtent => 50;
@override
bool shouldRebuild(covariant oldDelegate) => false;
}
Key concepts:
CustomScrollViewis the container that accepts sliversSliverAppBarcreates collapsible headers withpinned/floatingoptionsSliverPersistentHeadercreates sticky sectionsSliverGridandSliverListreplace regular Grid/ListView inside CustomScrollView
Try It Yourself
Modify the example to add a SliverToBoxAdapter between the header and grid that displays a horizontal scrolling list of categories. This teaches you how to mix different sliver types and embed non-sliver widgets.
SliverToBoxAdapter(
child: Container(
height: 60,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) => Chip(label: Text('Category $index')),
),
),
),
Tip of the Day
Use SliverFillRemaining when you need a widget to fill the remaining viewport space—perfect for empty states or loading indicators that should center in available space regardless of other content.