Flutter - How to override scroll physics

6,974

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 ListViews 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.

Share:
6,974
scrimau
Author by

scrimau

Updated on December 13, 2022

Comments

  • scrimau
    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?