我正在尝试动态设置PageView边界。 这是一个简化的示例,从第10页开始,由随机数生成器(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在PageView.builder内部更改(基于打印结果(1)),但在CustomScrollPhysics中没有更改(无打印结果(2))。
有人可以解释一下这里发生了什么吗? 这是为PageView设置动态边界的正确方法吗?
答案 0 :(得分:1)
ScrollPhysics
所延伸的 CustomScrollPhysics
被标记为不可变。即使您在itemBuilder
内更改其布尔值,实际的布尔值也不会更改(如未在leftEnd
中打印rightEnd
和applyBoundaryConditions
所示)。我没有官方解释,为什么您的scrollPhysics.leftEnd
中的itemBuilder
在类本身未更改的情况下显示所需的已更改布尔值,但我想这是因为您没有设置那些变量应为final
,应有尽有,并且没有任何阻碍您进行更改,因此scrollPhysics
中的本地_MyTabbedPageState
会显示这些更改,即使它们在内部未更改。 isGoingLeft
之所以要打印,是因为它是在CustomScrollPhysics
本身内部而不是从外部进行更改,如itemBuilder
所示。
作为快速解决方案,我创建了另一个类:
class Status {
bool leftEnd = false;
bool rightEnd = false;
bool isGoingLeft = false;
}
稍微更改了您的CustomScrollPhysics
:
class CustomScrollPhysics extends ScrollPhysics {
final Status status;
CustomScrollPhysics(this.status, {ScrollPhysics parent})
: super(parent: parent);
@override
CustomScrollPhysics applyTo(ScrollPhysics ancestor) {
return CustomScrollPhysics(this.status, parent: buildParent(ancestor));
}
...
并在您处于状态的构造函数调用中添加了Status
实例:
CustomScrollPhysics scrollPhysics = CustomScrollPhysics(Status());
对this.status
中的CustomScrollPhysics
进行所有更改。现在它应该可以按预期工作了。