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 ListView
s 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:
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:
ClampingScrollPhysics
ClampingScrollPhysics
prevents the scroll offset from reaching beyond the bounds of the content, the typical behavior on Android.
Output:
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:
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:
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: