Pagination is an integral part of almost every app, it lets us load data in small chunks, hence not waiting an eternity for whole data to be loaded at once.
The conventional way of doing it in Flutter is by using a scroll controller; you add a listener to the scroll controller and as soon as you reach the bottom of the screen, more data is loaded and you continue scrolling till the next chunk of data is fetched, and so the cycle continues.
Problem in NestedScrollView
But what if you want a sliver effect too in your screen as well as paginate your data. Well we all know that one of the ways to achieve this is NestedScrollView.
Let’s take a look at an example app which has the above mentioned features in it.
List<int>_list=[1,2,3,4,5,6,7,8,9,10]; Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: NestedScrollView( controller: scrollController, headerSliverBuilder: (context,val)=>[ SliverAppBar( centerTitle: true, leading: FlutterLogo(), title: Text("Flutter ScrollNotification"), ), SliverPersistentHeader(delegate: Delegate(),pinned: true,) ], body: SingleChildScrollView( padding: EdgeInsets.symmetric(horizontal: 10), child: Column( children:List.generate(_list.length, (index) => Padding( padding: EdgeInsets.symmetric(vertical: 10), child: Material( elevation: 4, child: ListTile( title: Text(index.toString()), ), ), )), ), ), ), ), ); } class Delegate extends SliverPersistentHeaderDelegate { @override double get minExtent => 100; @override double get maxExtent => 250; @override Widget build( BuildContext context, double shrinkOffset, bool overlapsContent) { return Container( color: Colors.purpleAccent[400], child: FlutterLogo( size: 250, ), ); } @override bool shouldRebuild(Delegate oldDelegate) { return false; } }
We add a listener to scrollController which is assigned to NestedScrollView, to paginate our data the conventional way.
ScrollController scrollController; initState(){ super.initState(); scrollController=ScrollController(); scrollController.addListener(() { if (scrollController.offset >= scrollController.position.maxScrollExtent && !scrollController.position.outOfRange){ final tempList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; setState(()=>_list.addAll(tempList)); } }); }
Each time we scroll to the bottom of the screen the listener should append our list and our scrolling should continue. Let’s have a look at our app.
As you can see above, pagination works perfectly fine the first time, but after that our pagination stops working, and we have to scroll a little bit up and then again scroll down for it to work.
This happens because once the outer scrollable has reached its full extent, then the inner scrollable will scroll. The outer scrollable is no longer scrolling, so it no longer receives notifications.
And if we assign a scrollController to the inner singleChildScrollView, it will break the link with NestedScrollView and we won’t have the sliver effect.
Solution
To overcome this nightmare, instead of using scrollController we use NotificationListener on inner SingleChildScrollView, as we know that scrollable widgets dispatch scrollNotifications!
We can now use a NotificationListener of type ScrollNotification to listen to notification updates of our scrolling, and as soon as we reach the bottom of the screen we can append the list, as follows:
NotificationListener<ScrollNotification>(
onNotification: (notification) {
if (notification is ScrollEndNotification) {
if (notification.metrics.pixels ==
notification.metrics.maxScrollExtent) {
final tempList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
setState(() => _list.addAll(tempList));
return true;
}
}
return true;
},
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 10),
child: Column(
children: List.generate(
_list.length,
(index) => Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Material(
elevation: 4,
child: ListTile(
title: Text(index.toString()),
),
),
)),
),
),
)
Here we go, everything is working just perfectly. To learn more about NotificationListeners head to officials docs.
You can view the complete source code here
First time here, wish you good!
Where there is a will, there is a way.