Search code examples
flutterflutter-pageview

PageView with different ScrollPhysics for first and last pages


How can I customize the physics property of PageView to have for example a ClampingScrollPhysics for the first page (edge overflow) and a BouncingScrollPhysics for the last page?

(My use case is to load pages on demand when scrolling the last page.)


Solution

  • I tested this very little, so make sure you test it properly.

    Code (see comments):

    class MyScrollPhysics extends ScrollPhysics {
      const MyScrollPhysics({super.parent});
    
      @override
      MyScrollPhysics applyTo(ScrollPhysics? ancestor) {
        return MyScrollPhysics(parent: buildParent(ancestor));
      }
    
      @override
      double applyBoundaryConditions(ScrollMetrics position, double value) {
        /// This is the important part, where we can allow overscrolling of the
        /// list, but not underscrolling.
    
        if (value < position.pixels &&
            position.pixels <= position.minScrollExtent) {
          // Underscroll.
          return value - position.pixels;
        }
    
        if (value < position.minScrollExtent &&
            position.minScrollExtent < position.pixels) {
          // Hit top edge.
          return value - position.minScrollExtent;
        }
    
        /// If it's not a left or top boundary, then we allow overscrolling.
        return .0;
      }
    
      @override
      Simulation? createBallisticSimulation(
        ScrollMetrics position,
        double velocity,
      ) {
        final tolerance = toleranceFor(position);
    
        /// The simulation will be the typical bouncing scroll simulation.
        if (velocity.abs() >= tolerance.velocity || position.outOfRange) {
          return BouncingScrollSimulation(
            spring: spring,
            position: position.pixels,
            velocity: velocity,
            leadingExtent: position.minScrollExtent,
            trailingExtent: position.maxScrollExtent,
            tolerance: tolerance,
            constantDeceleration: .0,
          );
        }
    
        return null;
      }
    }
    

    Usage:

    PageView(
      physics: const MyScrollPhysics(),
      children: [
        Container(color: Colors.red),
        Container(color: Colors.green),
        Container(color: Colors.blue),
      ],
    );