Flutter - ScrollPhysics Types with Examples

This tutorial explains the differences between scroll physics in Flutter along with the examples.

Flutter has some widgets that simplify displaying a list of items. Usually, the layout allows the users to perform scrolls. If you ever use scroll views in different apps, you may notice different scroll effects or behavior, also known as scroll physics. Some built-in widgets in Flutter also allows us to set the scroll physics to use. Flutter also provides some predefined physics that we can use. In this tutorial, I'm going to explain the differences between the predefined physics.

Set ScrollPhysics

ScrollPhysics is a class that defines the physics of a scrollable widget. It can determine the behavior when the user stops scrolling or reaches the maximum scroll extent.

Some Flutter widgets that extend ScrollView allow you to define the physics to use. You need to pass the ScrollPhysics to the constructor of the widget. Some of the widgets that allow you to define the physics include ListView, PageView, GridView, and CustomScrollView. For this tutorial, we are going to create several ListViews with different scroll physics, using the class below as the item.

  class Item extends StatelessWidget {
  
    final int index;
  
    const Item({super.key, required this.index});
  
    @override
    Widget build(BuildContext context) {
      return SizedBox(
        height: 50,
        child: Card(
          color: Colors.pinkAccent,
          child: Center(
            child: Text(
              'Item: ${index + 1}',
              style: const TextStyle(color: Colors.white),
            ),
          ),
        ),
      );
    }
  }

Here is an example of how to pass the argument for setting the scroll physics to use.

  class ScrollPhysicsExample extends StatelessWidget {
  
    const ScrollPhysicsExample({super.key});
  
    @override
    Widget build(BuildContext context) {
      return Padding(
        padding: const EdgeInsets.all(0.0),
        child: ListView.builder(
          physics: const NeverScrollableScrollPhysics(), // the scroll physics to use
          itemCount: 20,
          itemBuilder: (BuildContext context, int index) {
            return Item(index: index);
          },
        ),
      );
    }
  }

Below are the explanations and examples of some predefined scroll physics.

NeverScrollableScrollPhysics

NeverScrollableScrollPhysics is a scroll physics that does not allow the user to scroll. So, if the user tries to scroll, it will not have any effect.

Output:

Flutter - NeverScrollableScrollPhysics

AlwaysScrollableScrollPhysics

AlwaysScrollableScrollPhysics is a scroll physics that always lets the user scroll. Scrolling won't be disabled even when there is no content to scroll. Since there's no scrollable content, you may not see the scroll effect. To see the effect, you can use a NotificationListener like in the example below.

  class AlwaysScrollableScrollPhysicsExample extends StatelessWidget {
  
    const AlwaysScrollableScrollPhysicsExample({super.key});
  
    @override
    Widget build(BuildContext context) {
      return Padding(
        padding: const EdgeInsets.all(0.0),
        child: NotificationListener(
          child: ListView.builder(
            // physics: const NeverScrollableScrollPhysics(),
            physics: const AlwaysScrollableScrollPhysics(),
            itemCount: 5,
            itemBuilder: (BuildContext context, int index) {
              return Item(index: index);
            },
          ),
          onNotification: (scrollNotification) {
            if (scrollNotification is ScrollStartNotification) {
              print('Widget has started scrolling');
            }
            return true;
          },
        ),
      );
    }
  }

BouncingScrollPhysics

BouncingScrollPhysics allows the scroll offset to go beyond the bounds of the content and immediately bounce to the bounds. When the overscroll happens, it shows a bouncing effect.

Output:

Flutter - BouncingScrollPhysics

ClampingScrollPhysics

ClampingScrollPhysics prevents the scroll offset from reaching beyond the bounds of the content, the typical behavior on Android.

Output:

Flutter - ClampingScrollPhysics

PageScrollPhysics

PageScrollPhysics is the scroll physics used by a PageView by default. It causes the view to snap to page boundaries. It can also be used by some other scrollable widgets other than PageView. If you use it, each scroll can only land on the next or previous 'page'.

Output:

Flutter - PageScrollPhysics

For a PageView, you can use another physics by setting the pageSnapping to false. Then, pass the ScrollPhysics to be used as the physics argument.

FixedExtentScrollPhysics

FixedExtentScrollPhysics only allows each scroll to land on an item, giving a snapping effect. It must be used with a scrollable that uses a FixedExtentScrollController. A FixedExtentScrollController itself can only be used with a ListWheelScrollView. Below is an example of a ListWheelScrollView with FixedExtentScrollPhysics.

  class FixedExtentScrollPhysicsExample extends StatelessWidget {
  
    final FixedExtentScrollController _fixedExtentScrollController =   FixedExtentScrollController();
  
    FixedExtentScrollPhysicsExample({super.key});
  
    @override
    Widget build(BuildContext context) {
      return Padding(
        padding: const EdgeInsets.all(0.0),
        child: ListWheelScrollView(
          controller: _fixedExtentScrollController,
          physics: const FixedExtentScrollPhysics(),
          itemExtent: 50,
          children: List.generate(20, (index) => Item(index: index)),
        ),
      );
    }
  }

Output:

Flutter - FixedExtentScrollPhysics

RangeMaintainingScrollPhysics

RangeMaintainingScrollPhysics is a scroll physics that tries to keep the scroll position in range when dimension changes suddenly. The behaviors can be seen below, a bit more difficult to be understood compared to the others.

  • If the current velocity is non-zero, there will be no adjustment made.
  • If the extents haven't changed, the overscroll adjustment will not be made.
  • If the position changed since the last animation frame, the overscroll will not be maintained.
  • If the position changed and the boundaries were and still are finite, the boundary will not be enforced.
  • If the range was out of range, the boundary will not be enforced.
  • If the range was in range and the boundary is to be enforced, calculate the new position by deferring the other physics and clamp to the new range.

Summary

Flutter provides some scroll physics that can be used to customize the behavior of a scrollable widget. You can use them on widgets that let you define the scroll physics. You can also create your own physics if you need a custom one.

You can also read about: