Skip to content

Getting scrolling events using ScrollController

Flutter, Flutter Tips, Widgets1 min read

When you're working on a Flutter project you'll probably be using ListViews and at some point you might want to monitor scrolling events so you can add pagination or lazy loading if you're fetching data in some way. This post quickly runs through how to listen to scrolling events from a ListView using ScrollController.


ScrollController is a class in Flutter that's made to - you guessed it - control a widget that scrolls. It's the same sort of concept as TabController or TextEditingController. It can be used to monitor scrolling events or jump to a certain position in a list. To kick things off first you'll need to create an instance of ScrollController:

1ScrollController _controller = ScrollController();

Keep in mind this assumes you're going to use it with a ListView widget, and everything is inside the State portion of a StatefulWidget. You're also going to need to create a void to call when new events are received:

1void _onScrollEvent() {
2 final extentAfter = _controller.position.extentAfter;
3 print("Extent after: $extentAfter");

The method above is going to check position(specifically extentAfter) and print the current value to the console. The extentAfter value is essentially how many pixels or points there are left until you hit the bottom of the list, so this value should be zero once you reach the end of the last item in the list.

Adding and removing the listener

Now you just need to hook up the controller to the _onScrollEvent method, you can do this in initState and dispose:

2void initState() {
3 _controller.addListener(_onScrollEvent);
4 super.initState();
8void dispose() {
9 _controller.removeListener(_onScrollEvent);
10 super.dispose();

All that's left to do now is wire up the ScrollController to your ListView widget. Here's what the build method of my widget looks like for this example:

2Widget build(BuildContext context) {
3 return ListView.builder(
4 controller: _controller,
5 itemCount: 50,
6 itemBuilder: (context, index) {
7 return ListTile(
8 title: Text('List Item ${index + 1}')
9 );
10 }
11 );

So all you really need to do is specify _controller for the controller prop. And that's all there is to it. If you're trying to implement lazy loading you could load your new items after extentAfter reaches a certain point, for example 200 pixels:

1void _onScrollEvent() {
2 final extentAfter = _controller.position.extentAfter;
3 print("Extent after: $extentAfter");
4 if (extentAfter < 300) {
5 // Load new items
6 }

There's also other values you can look at like extentBefore for example, which is basically the opposite of extentAfter. If you want to see a full example you can check it out in DartPad here.