Flutter - How to override scroll physics
So, i found a working solution.
It looks like it's essentiell for a custom scroll physics to override the way it is constructed and applied to be usable in ListView
s such as the ListWheelScrollView
. For this purpose one has to implement a constructor with a parent
argument and call super(parent:parent)
of the base ScrollPhysics
class. Then one has to override the applyTo
method to return an instance of ones custom scroll physics class with the ancestor
argument wrapped in buildParent(ancestor)
as parent
argument for the constructor. Then it gets actually applied correctly. So an example for a FixedExtentScrollPhysics
with disabled flinging is:
class CustomScrollPhysics extends FixedExtentScrollPhysics {
const CustomScrollPhysics({ScrollPhysics parent})
: super(parent: parent);
@override
double get minFlingVelocity => double.infinity;
@override
double get maxFlingVelocity => double.infinity;
@override
double get minFlingDistance => double.infinity;
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(parent: buildParent(ancestor));
}
}
Since this appears to be how every ScrollPosition
is implemented, it looks like it's the implied way of doing this sort of thing. Couldn't find any documentation on this and dont rly know, if this is the 'correct' way.
scrimau
Updated on December 13, 2022Comments
-
scrimau over 1 year
How does one actually override the scroll physics for a flutter ListView?
In my concrete use case, i want to override the scroll physics of a ListWheelScrollView, so that a simulated scroll after a release of the pan is only simulated with maximum velocity and "too fast" flinging is disabled.
What i tried so far:
I create a custom scroll physics class:
class CustomScrollPhysics extends FixedExtentScrollPhysics { @override double get minFlingVelocity => double.infinity; @override double get maxFlingVelocity => double.infinity; @override double get minFlingDistance => double.infinity; @override SpringDescription get spring => SpringDescription.withDampingRatio(ratio: 0.7); }
My reasoning here was to disable flinging by setting the Fling velocity and distance to infinity and using an underdamped spring to slow down the ballistic scroll animation.
Using it like this:
ListWheelScrollView.useDelegate( physics: CustomScrollPhysics(), clipToSize: true, useMagnifier: false, controller: scrollController, itemExtent: widget.itemExtent, childDelegate: ListWheelChildBuilderDelegate( builder: (context, toBuild) => toBuild < widget.min || toBuild > widget.max ? null : buildNumberWidget(context, toBuild), ), ),
This accomplished absolutely nothing, then i found this, so i added:
class CustomScrollPhysics extends FixedExtentScrollPhysics { //.... @override FixedExtentScrollPhysics applyTo(ScrollPhysics ancestor) { return CustomScrollPhysics(); } }
This accomplishes something, but breaks the listview, specifically it now overflows at the ends and it throws exception after a drag:
Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 480 pos 12: '_drag == null': is not true.
This behaviour is also independent of the other changes, they still not rly do anything. So it obviously has to do with how the scroll physics are combined, so i tried to use the applyTo methods of FixedExtentScrollPhysics and ScrollPhysics, but still no luck. Im wondering, how does one actually override the scroll physics of a list view in flutter? Is one supposed to implement a subclass? Do i have to use the applyTo methods in a different manner? Is there no easy way to override spring/fling behaviour and im pretty much stuck with the given classes?