In Flutter, with slivers, we can create different scrolling effects. Slivers give an amazing view of the lists when they scroll up or down. The slivers allow us to impact the Lists, Grids scrolling experience. In this article, we will be looking at Slivers features offered by the sliver_tools package. The features sliver_tools offers are as follows:
- MultiSliver
- SliverStack
- SliverClip
- SliverAnimatedPaintExtent
Add the dependency
In the pubspec.yaml file, add sliver_tools as a dependency then configure it by running pub get.
dependencies: sliver_tools: ^0.2.5
|
Import dependency
In the main.dart file, add dependency as follows:
import 'package:sliver_tools/sliver_tools.dart' ;
|
Implementation
The Slivers should be wrapped inside CustomScrollView to give a scrolling effect to lists or grids. CustomScrollView wraps Slivers widget which includes all the slivers we create.
MultiSliver
The MultiSliver() widget allows wrapping multiple slivers together. For Example, in the below code we are creating a SliverPinnedHeader() – a header that will stick to the top even list reaches the end of the screen and SliverList() widgets inside a single MultiSliver() widget.
MultiSliver( // defaults to false
pushPinnedChildren: true ,
children: <Widget>[
SliverPinnedHeader(
child: Container(
color: Colors.yellow,
height: 100,
child: Text(
"I am a Pinned Header" ,
style: TextStyle(fontSize: 30),
))),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color:
index % 2 == 0 ? Colors.green : Colors.greenAccent,
height: 80,
alignment: Alignment.center,
child: Text(
"Item $index" ,
style: const TextStyle(fontSize: 30),
),
),
);
},
// 40 list items
childCount: 40,
),
),
],
)
|
Output:
SliverStack
The SliverStack() allows putting one sliver on another. In the below example, through SliverPositioned() we are creating the complete layout of yellow color on top of which we are rendering list items using SliverList(). SliverList() takes a delegate as a parameter to give the items to the list to be scrolled.
SliverStack( // defaults to false
insetOnOverlap: true ,
children: <Widget>[
SliverPositioned.fill(
child: Container(color: Colors.yellow),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
color:
index % 2 == 0 ? Colors.green : Colors.greenAccent,
height: 40,
alignment: Alignment.center,
child: Text(
"Item $index" ,
style: const TextStyle(fontSize: 30),
),
),
);
},
// 40 list items
childCount: 40,
),
),
],
)
|
Output:
SliverGrid
SliverGrid() puts the items in a 2D system. It requires gridDelegate that structures the grid layout and a delegate that passes items to be presented on screen for scrolling. The parameter childCount is the number of items to be displayed.
SliverGrid( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 2.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: 20,
color: Colors.amber[100],
alignment: Alignment.center,
child: Text(index.toString()),
);
},
childCount: 41,
),
)
|
Output:
A Full Example
import 'package:flutter/material.dart' ;
import 'package:sliver_tools/sliver_tools.dart' ;
void main() {
runApp( const MyApp());
} class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false ,
title: 'SliverList in Flutter' ,
theme: ThemeData(primarySwatch: Colors.green),
home: HomePage(),
);
}
} class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
} class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text( "GeeksForGeeks" ),
centerTitle: true ,
),
body: CustomScrollView(slivers: [
SliverPinnedHeader(
child: Container(
color: Colors.blue[100],
height: 100,
child: Text(
"I am a Pinned Header" ,
style: TextStyle(fontSize: 30),
))),
SliverAnimatedPaintExtent(
duration: const Duration(milliseconds: 150),
child: SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
color: Colors.pink[100],
height: 40,
alignment: Alignment.center,
child: Text(
"$index" ,
style: const TextStyle(fontSize: 30),
),
),
);
},
// 40 list items
childCount: 10,
),
),
),
SliverStack(
// defaults to false
insetOnOverlap: true ,
children: <Widget>[
SliverPositioned.fill(
child: Container(color: Colors.yellow),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(15.0),
child: Container(
color:
index % 2 == 0 ? Colors.green : Colors.greenAccent,
height: 40,
alignment: Alignment.center,
child: Text(
"Item $index" ,
style: const TextStyle(fontSize: 30),
),
),
);
},
// 40 list items
childCount: 10,
),
),
],
),
SliverGrid(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
childAspectRatio: 2.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(
height: 20,
color: Colors.amber[100],
alignment: Alignment.center,
child: Text(index.toString()),
);
},
childCount: 41,
),
)
]));
}
} |
Output: