I'm trying to set PageView boundary dynamically. Here's a simplified example, which starts page 10, and left and right boundary is set by random number generator (leftEnd, rightEnd).
import 'package:flutter/material.dart';
import 'dart:math';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyTabbedPage(),
);
}
}
class MyTabbedPage extends StatefulWidget {
const MyTabbedPage({Key key}) : super(key: key);
@override
_MyTabbedPageState createState() => new _MyTabbedPageState();
}
class _MyTabbedPageState extends State<MyTabbedPage> with SingleTickerProviderStateMixin {
final leftEnd = Random().nextInt(5);
final rightEnd = 10 + Random().nextInt(5);
CustomScrollPhysics scrollPhysics = CustomScrollPhysics();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: PageView.builder(
controller: PageController(initialPage: 10),
physics: scrollPhysics,
itemBuilder: (context, index) {
scrollPhysics.leftEnd = (index <= leftEnd);
scrollPhysics.rightEnd = (index >= rightEnd);
// --------- print (1) ----------
print("is leftEnd: ${index <= leftEnd}");
print("is rightEnd: ${index >= rightEnd}");
print("scrollphysics.leftEnd: ${scrollPhysics.leftEnd}");
print("scrollphysics.rightEnd: ${scrollPhysics.rightEnd}");
return Center(
child: Text("Item $index"),
);
}
));
}
}
class CustomScrollPhysics extends ScrollPhysics {
CustomScrollPhysics({ScrollPhysics parent}) : super(parent: parent);
bool leftEnd = false;
bool rightEnd = false;
bool isGoingLeft = false;
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(parent: buildParent(ancestor));
}
@override
double applyPhysicsToUserOffset(ScrollMetrics position, double offset) {
isGoingLeft = offset.sign < 0;
return offset;
}
@override
double applyBoundaryConditions(ScrollMetrics position, double value) {
//print("applyBoundaryConditions");
assert(() {
if (value == position.pixels) {
throw FlutterError(
'$runtimeType.applyBoundaryConditions() was called redundantly.\n'
'The proposed new position, $value, is exactly equal to the current position of the '
'given ${position.runtimeType}, ${position.pixels}.\n'
'The applyBoundaryConditions method should only be called when the value is '
'going to actually change the pixels, otherwise it is redundant.\n'
'The physics object in question was:\n'
' $this\n'
'The position object in question was:\n'
' $position\n');
}
return true;
}());
if (value < position.pixels && position.pixels <= position.minScrollExtent)
return value - position.pixels;
if (position.maxScrollExtent <= position.pixels && position.pixels < value)
// overscroll
return value - position.pixels;
if (value < position.minScrollExtent &&
position.minScrollExtent < position.pixels) // hit top edge
return value - position.minScrollExtent;
if (position.pixels < position.maxScrollExtent &&
position.maxScrollExtent < value) // hit bottom edge
return value - position.maxScrollExtent;
// --------- print (2) ----------
if (leftEnd) print("leftEnd");
if (rightEnd) print("rightEnd");
if (isGoingLeft) print("isGoingLeft");
if (leftEnd && !isGoingLeft) {
return value - position.pixels;
} else if (rightEnd && isGoingLeft) {
return value - position.pixels;
}
return 0.0;
}
}
scrollphysics.leftEnd/rightEnd changes inside PageView.builder (based on the print (1)), but it doesn't change in CustomScrollPhysics (no print (2)).
Could anyone explain what's happening here? Is this the right way to set a dynamic boundary for PageView?