Flutter - Using ScrollController Examples

This tutorial shows you how to use ScrollController in Flutter.

It's very common to have a scroll view if the content to be displayed cannot fit into the screen. Creating such a view can be done in Flutter as well. Sometimes, you may need to do additional things, such as handling when the user performs a scroll or getting the current scroll offset. For those purposes, you can use a built-in class in Flutter named ScrollController.

Using ScrollController

ScrollController is a controller for a scrollable widget. It's usually stored as member variables in State classes and can be reused every time the build method is called. It can be used in multiple scrollable widgets, though you can't do it for certain uses. Below is the constructor of ScrollController.

  ScrollController({
    double initialScrollOffset = 0.0,
    bool keepScrollOffset = true,
    String? debugLabel,
    void Function(ScrollPosition)? onAttach,
    void Function(ScrollPosition)? onDetach,
  })

There is no required argument. For the basic usage, we are going to create an instance of it without passing any argument. You have to pass it as the argument of a widget that accepts a ScrollController as the argument. There are some widgets having that type of argument such as ListView, GridView, and CustomScrollView.

Set ScrollController of a Widget

In this tutorial, we are going to set the ScrollController of a ListView. First, create the instance and store it as a member variable of a State class. The ListView widget has an argument named controller. You need to pass the instance as the controller argument. The usage for other types of widget is very similar.

  class MyPageState extends State<MyPage> {
  
    late final ScrollController _controller;
  
    @override
    void initState() {
      super.initState();
      _controller = ScrollController();
    }
  
    @override
    Widget build(BuildContext context) {
      return Column(
        children: [
          Expanded(
            child: ListView.separated(
              controller: _controller,
              itemCount: 50,
              itemBuilder: (_, int index) {
                return Padding(
                  padding: const EdgeInsets.symmetric(
                    vertical: 10.0,
                    horizontal: 20.0,
                  ),
                  child: Text('Item $index'),
                );
              },
              separatorBuilder: (BuildContext context, int index) {
                return const Divider(
                  indent: 20,
                  endIndent: 20,
                  thickness: 2,
                );
              },
            ),
          ),
        ],
      );
    }
  }

A ScrollController instance can be used by more than one scroll view. That means you can pass the same instance to be the controller of multiple widgets. However, there are some limitations which will be explained later.

Set Initial Offset

By default, Flutter will display the uppermost content initially. In other words, the initial offset is 0. To set the initial offset, you can pass an argument named initialScrollOffset to the constructor of ScrollController.

  ScrollController(
    initialScrollOffset: 200.0,
    // other arguments
  );

Handle Restoring Offset

By default, Flutter can save the current scroll offset using PageStorage and restore it when the controller's scrollable is recreated. You can change that behavior by passing a boolean value as the keepScrollOffset argument which defaults to true. If you change it to false, Flutter won't remember the scroll offset and thus resetting the offset when the scrollable is recreated.

  ScrollController(
    keepScrollOffset: false,
    // other arguments
  );

Get Current Scroll Offset

The current scroll offset can be obtained by accessing the offset property of the ScrollController.

  double currentOffset = _controller.offset;

However, if you want to access the offset property, you can only pass it to one scroll view. Otherwise, if it's passed to multiple scroll views, you'll get the following error.

  The following assertion was thrown while dispatching notifications for ScrollController:
  ScrollController attached to multiple scroll views.
  'package:flutter/src/widgets/scroll_controller.dart':
  Failed assertion: line 156 pos 12: '_positions.length == 1'

Get Current ScrollPosition

To get more detailed information, you can access a ScrollPosition object by accessing the position property. Like the offset property, it can only be accessed if there is only one scroll view.

  ScrollPosition currentScrollPosition = _controller.position;

Below is the output example.

  ScrollPositionWithSingleContext#ff02a(offset: 448.0, range: 0.0..2076.6, viewport: 507.4, ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, BallisticScrollActivity#041e1(AnimationController#51ec4(⏭ 447.965; paused; for BallisticScrollActivity)), ScrollDirection.reverse)

Animate to Offset

ScrollController also allows you to animate the current scroll position to a particular position programmatically. It can be done by calling the animateTo method. It has one positional argument which indicates the offset to scroll to. There are also optional named arguments which can be used to customize the duration and curve of the animations.

  Future  animateTo(
    double offset,
    {
      required Duration duration,
      required Curve curve,
    }
  )

Below is an example that sets the offset to 100 with an animation duration of 500 milliseconds and a fastLinearToSlowEaseIn animation curve.

  _scrollController.animateTo(
    100,
    duration: const Duration(milliseconds: 500),
    curve: Curves.fastLinearToSlowEaseIn
  );

ScrollController Parameters

  • double initialScrollOffset: The initial offset value. Defaults to 0.0.
  • bool keepScrollOffset: Whether to save the current offset with PageStorage each time a scroll completes and restore it if the scrollable is recreated. Defaults to true.
  • String? debugLabel: A label to be used as the output of toString.
  • void Function(ScrollPosition)? onAttach: Function to be called when a ScrollPosition is attached to the controller.
  • void Function(ScrollPosition)? onDetach: Function to be called when a ScrollPosition is detached from the controller..

Summary

That's how to use ScrollController in Flutter. You can pass an instance of it to certain widgets with scroll support. Then, you can use it to control the scroll position and get the current offset position.

You can also read about: