使用自定义ScrollPhysics调整具有动态边界的PageView [英] flutter PageView with dynamic boundary using custom ScrollPhysics
问题描述
我正在尝试动态设置PageView边界.这是一个简化的示例,从第10页开始,由随机数生成器(leftEnd,rightEnd)设置左右边界.
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在PageView.builder内部更改(基于打印结果(1)),但在CustomScrollPhysics中没有更改(无打印结果(2)).
scrollphysics.leftEnd/rightEnd changes inside PageView.builder (based on the print (1)), but it doesn't change in CustomScrollPhysics (no print (2)).
有人可以解释这里发生了什么吗?这是为PageView设置动态边界的正确方法吗?
Could anyone explain what's happening here? Is this the right way to set a dynamic boundary for PageView?
推荐答案
ScrollPhysics
被标记为不可变.即使您在 itemBuilder
中更改其布尔值,实际的布尔值也不会更改(如未在中打印
).我没有正式的解释,为什么您的 leftEnd
和 rightEnd
applyBoundaryConditions itemBuilder
中的 scrollPhysics.leftEnd
为什么在类本身未更改的情况下显示所需的已更改布尔值,但我猜是这样是因为您没有将这些变量设置为 final
,并且没有任何阻碍您更改它们,所以您在 _MyTabbedPageState
scrollPhysics >会显示这些更改,即使它们在内部未更改也是如此. isGoingLeft
只会被打印,因为它是在 CustomScrollPhysics
本身内部进行更改,而不是从外部进行更改,如 itemBuilder
中所示.
ScrollPhysics
which your CustomScrollPhysics
is extending from is marked as immutable. Even though you are changing its booleans inside your itemBuilder
the actual booleans are not changed (as seen by not printing leftEnd
and rightEnd
in applyBoundaryConditions
). I don't have an official explanation as why scrollPhysics.leftEnd
in your itemBuilder
shows the desired changed boolean while it didn't change in it's class itself but i would guess it is because you didn't set those variables as final
as they should be and nothing is holding you back to change them so your local scrollPhysics
in _MyTabbedPageState
is showing those changes even though they are not changed internally. isGoingLeft
is only getting printed because it is being changed inside the CustomScrollPhysics
itself rather then from the outside as seen in itemBuilder
.
作为快速解决方案,我创建了另一个类:
As a quick fix i created another class:
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
实例:
and added a Status
instance inside the constructor call in your state:
CustomScrollPhysics scrollPhysics = CustomScrollPhysics(Status());
对 CustomScrollPhysics
中的 this.status
进行所有更改.现在它应该可以按预期工作了.
Apply every change to this.status
inside CustomScrollPhysics
. Now it should work as you intended.
这篇关于使用自定义ScrollPhysics调整具有动态边界的PageView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!