I'd like to create a progression PageView
with custom ScrollPhysics
, 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):
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 scroll_physics.dart
for the iOS and Android implementations. But I'm still stuck.
I tried this here 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.
Here's my code right now:
Called from:
PageView(
controller: PageController(
initialPage: model.initallPage,
),
children: pages,
physics: model.currentPage >= model.lastAccessiblePage ? CustomScrollPhysics(CustomScrollStatus()..rightEnd = true) : ScrollPhysics(),
onPageChanged: (value) {
model.currentPage = value;
},
),
Custom ScrollPhysics:
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 < 0;
return offset;
}
@override
double applyBoundaryConditions(ScrollMetrics position, double value) {
if (value < position.pixels && position.pixels <= position.minScrollExtent) {
print('underscroll');
return value - position.pixels;
}
if (position.maxScrollExtent <= position.pixels && position.pixels < value) {
print('overscroll');
return value - position.pixels;
}
if (value < position.minScrollExtent && position.minScrollExtent < position.pixels) {
print('hit top edge');
return value - position.minScrollExtent;
}
if (position.pixels < position.maxScrollExtent && position.maxScrollExtent < 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 > accesssible page
print('default');
return 0.0;
}
}
Edit:
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.
children: pages