In this article, we’ll learn how to use CustomScrollView and Slivers to create a custom scrolling screen with multiple scrollable components scrolling horizontally, vertically, or simply putting a non-scrollable widget inside CustomScrollView.
This widget is especially useful if you want to create custom scrolling effects or have more control over ScrollView’s scrolling content.
If you build a custom ScrollView like mine, you should end up with this result:
Table of contents
- What exactly are Slivers?
- Understanding CustomScrollView
- Introduction to Slivers
- Building the custom Flutter ScrollView
What exactly are Slivers?
A sliver is a portion of a scrollable area that you can configure to behave differently.
As the official docs state, a sliver is a small portion of a scrollable area inside a CustomScrollview that can be configured accordingly to behave in a certain way. Using Flutter’s Slivers, we can easily create a plethora of fantastic scrolling effects. Slivers are used by all scrollable views in Flutter; for example, ListView uses SliverList and GridView uses SliverGrid.
Because Slivers lazily build their views when the widgets come into the viewport, it is really useful to show a great number of children without worrying about memory issues. Moreover, we can easily make lots of fantastic scrolling effects by using Flutter Slivers.
Understanding CustomScrollView
CustomScrollView is a widget that uses multiple Slivers rather than just one, as we saw with ListView and GridView. It enables you to directly utilize Slivers to create scrolling effects such as lists, grids, and expanding headers.
The implementation is straightforward; simply place all of the Slivers inside the CustomScrollView
as shown:
CustomScrollView( slivers: [ SliverAppBar(...), SliverToBoxAdapter(...), SliverGrid(...), SliverToBoxAdapter(...), SliverFixedExtenrList(...), ], controller: ScrollController(), )
Give CustomScrollView
a ScrollController
to control the initial scroll offset or to handle scroll behavior in general.
Introduction to Slivers
As previously stated, a Sliver is a portion of a scrollable area that can be used inside a CustomScrollView. There are numerous Slivers available, and we’ll select a few to demonstrate how to use them later.
- SliverAppBar: This sliver renders an app bar, and it is one of the most commonly used sliver widgets that creates collapsible
AppBars
by setting both theflexibleSpace
andexpandedHeight
parameters - SliverList: A sliver that renders a list in a linear array along the ScrollView’s main axis. To build list items as they scroll into view, SliverList accepts a delegate parameter. A
SliverChildListDelegate
specifies the fixed list of children that are created all at once, whereas aSliverChildBuilderDelegate
specifies how they are built lazily - SliverFixedExtentList: SliverFixedExtentList is identical to SliverList, with the exception that SliverFixedExtentList guarantees that all list items will have the same size on the main axis (i.e., equal height on a vertical scrolling list or equal width on a horizontal scrolling list). This has a significant impact on the performance of the ListView when scrolling because knowing the size of the items before loading them is quite beneficial when you wish to jump a long distance. For example, if we know each item is fixed at 50px tall and we want to scroll 5,000px down, we can easily leap 100 things by loading the 101st item and displaying it
- SliverGrid: SliverGrid is a sliver that displays a 2D array of children in a ScrollView. It accepts children via a delegate or an explicit list, and it also defines
gridDelegate
, which determines the location of the children widget within the grid - SliverPadding: A sliver that creates empty space around another sliver. The only difference between it and the Padding widget is that it generates RenderSliver rather than RenderBox, so that it can be used inside CustomScrollView
- SliverToBoxAdapter: A sliver that allows you to warp any other widget that isn’t a Sliver and use it inside CustomScrollView; this is a very useful sliver for creating intricate scrolling screens with various widgets
- SliverOpacity: A sliver widget that makes its sliver child partially transparent. It is an easy-to-use replacement to the Opacity widget, just like SliverPadding
Building the custom Flutter ScrollView
Enough talking; now it’s time to dive into the code and apply all we’ve learned about CustomScrollView and Slivers. We’ll build an example app with multiple scrollable/non-scrollable widgets aligned vertically in a scroll view that functions as a single scrollable area.
Here’s the structure of our CustomScrollView:
- SliverAppBar: A collapsible AppBar that expands and collapses as we scroll vertically. You can experiment with the
pinned
,floating
, andsnap
parameters to control how and when the SliverAppBar collapses, expands, or becomes pinned to the top as we scroll further - SliverToBoxAdapter: We’ll place a
Container
with height200
and colortealAccent
below theSliverAppBar
to represent a non-Sliver widget that needs to be wrapped withSliverToBoxAdapter
in order to be children ofCustomScrollView
SliverGrid: Underneath the Container is a SliverGrid with twenty child items each with a different color flavor of
tealAccent
. We usedSliverGridDelegateWithMaxCrossAxisExtent
, which selects the largest cross-axis extent for the tiles; if you want to create a layout with a fixed number of tiles in the cross axis, useSliverGridDelegateWithFixedCrossAxisCount
- SliverToBoxAdapter: Below
SliverGrid
, we have aContainer
widget again withamberAccent
color - ListView (Inside SliverToBoxAdapter): You might just be wondering why we used a
ListView
inside aSliverToBoxAdapter
. The reason is that we wanted to make a list that scrolls horizontally, which is not possible withSliverList
, and since we had to place this `ListView` insideCustomScrollView
, we need to add this insideSliverToBoxAdapter
- SliverFixedExtentList: As the final sliver child, we’re using
SliverFixedExtentList
to generate a vertically scrolling list with a fixeditemExtent
, which means that each child will have a fixed height, which will help us improve scrolling performance:
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); static const String _title = 'Flutter Code Sample'; @override Widget build(BuildContext context) { return const MaterialApp( title: _title, home: CustomScrollingWidget(), ); } } class CustomScrollingWidget extends StatefulWidget { const CustomScrollingWidget({Key? key}) : super(key: key); @override State createState() => _CustomScrollingWidgetState(); } class _CustomScrollingWidgetState extends State { @override Widget build(BuildContext context) { return Scaffold( body: CustomScrollView( slivers: [ const SliverAppBar( pinned: true, expandedHeight: 250.0, flexibleSpace: FlexibleSpaceBar( title: Text('CustomScrollView'), centerTitle: true, ), ), SliverToBoxAdapter( child: Container( color: Colors.tealAccent, alignment: Alignment.center, height: 200, child: const Text('This is Container'), ), ), SliverGrid( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200.0, mainAxisSpacing: 10.0, crossAxisSpacing: 10.0, childAspectRatio: 4.0, ), delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return Container( alignment: Alignment.center, color: Colors.teal[100 * (index % 9)], child: Text('Grid Item $index'), ); }, childCount: 20, ), ), SliverToBoxAdapter( child: Container( color: Colors.amberAccent, alignment: Alignment.center, height: 200, child: const Text('This is Container'), ), ), SliverToBoxAdapter( child: SizedBox( height: 100.0, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: 10, itemBuilder: (context, index) { return SizedBox( width: 100.0, child: Card( color: Colors.cyan[100 * (index % 9)], child: Text('Item $index'), ), ); }, ), ), ), SliverFixedExtentList( itemExtent: 50.0, delegate: SliverChildBuilderDelegate( (BuildContext context, int index) { return Container( alignment: Alignment.center, color: Colors.lightBlue[100 * (index % 9)], child: Text('List Item $index'), ); }, ), ), ], ), ); } }
Conclusion
In this article, you learned how to make a ScrollView with numerous scrolling components and now you can design any type of complicated scrollable screen using Slivers and CustomScrollView in this article. I hope you continue to explore new things.
Now that we’ve got everything ready, all you have to do is start the application and enjoy.
Best wishes! Have fun fluttering!
If you have any questions, please post them here. Any and all feedback is appreciated.
Get setup with LogRocket's modern error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side. - (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>