title: Custom Scroll Physics for progression PageView in Flutter
body: <p>I'd like to create a progression <code>PageView</code> with custom <code>ScrollPhysics</code>, so the user can only scroll to completed tabs. See following image for reference, top right is the progression (green = accessible, red = non accessible pages):</p>
  
  <p><img src="https://i.stack.imgur.com/n88m9.png" alt="1]"></p>
  
  <p>In the screenshot I completed page 1 and 2 and I don't want to allow the user to swipe to page 3 which is happening right now. I read the examples in <code>scroll_physics.dart</code> for the iOS and Android implementations. But I'm still stuck.</p>
  
  <p>I tried this <a href="https://stackoverflow.com/questions/55947158/flutter-pageview-with-dynamic-boundary-using-custom-scrollphysics">here</a> but it's bugged. You can prevent the user from going right but if the last accessible page isn't fully visible just like in the screenshot the 
  scrolling is already blocked and you can't scroll further to the right.</p>
  
  <p>Here's my code right now:</p>
  
  <p>Called from:</p>
  
  <pre><code>PageView(
            controller: PageController(
              initialPage: model.initallPage,
            ),
            children: pages,
            physics: model.currentPage &gt;= model.lastAccessiblePage ? CustomScrollPhysics(CustomScrollStatus()..rightEnd = true) : ScrollPhysics(),
            onPageChanged: (value) {
              model.currentPage = value;
            },
          ),
  </code></pre>
  
  <p>Custom ScrollPhysics:</p>
  
  <pre><code>class CustomScrollStatus {
    bool leftEnd = false;
    bool rightEnd = false;
    bool isGoingLeft = false;
    bool isGoingRight = false;
  }
  
  class CustomScrollPhysics extends ScrollPhysics {
    final CustomScrollStatus status;
  
    CustomScrollPhysics(
      this.status, {
      ScrollPhysics parent,
    }) : super(parent: parent);
  
    @override
    CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
      return CustomScrollPhysics(this.status, parent: buildParent(ancestor));
    }
  
    @override
    double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
      status.isGoingLeft = offset.sign &lt; 0;
      return offset;
    }
  
    @override
    double applyBoundaryConditions(ScrollMetrics position, double value) {
      if (value &lt; position.pixels &amp;&amp; position.pixels &lt;= position.minScrollExtent) {
        print('underscroll');
        return value - position.pixels;
      }
      if (position.maxScrollExtent &lt;= position.pixels &amp;&amp; position.pixels &lt; value) {
        print('overscroll');
        return value - position.pixels;
      }
      if (value &lt; position.minScrollExtent &amp;&amp; position.minScrollExtent &lt; position.pixels) {
        print('hit top edge');
        return value - position.minScrollExtent;
      }
      if (position.pixels &lt; position.maxScrollExtent &amp;&amp; position.maxScrollExtent &lt; value) {
        print('hit bottom edge');
        return value - position.maxScrollExtent;
      }
  
      if (status.leftEnd) print("leftEnd");
      if (status.rightEnd) print("rightEnd");
      if (status.isGoingLeft) print("isGoingLeft");
      if (status.isGoingRight) print("isGoingRight");
  
      // do something to block movement &gt; accesssible page
  
      print('default');
      return 0.0;
    }
  }
  </code></pre>
  
  <p>Edit:</p>
  
  <p>I thought about a completely different solution. Dynamically changing the children of the PageView. I'm still interested in overriding the `ScrollPhysics´ solution as it's cleaner in my opinion.</p>
  
  <p><code>children: pages</code></p>