如何处理 Flutter PageView 中的滚动视图手势?
How to handle scrollview gestures inside a Flutter PageView?
- 我的问题总结
目标
我的目标是展示长页面的轮播。
所以我使用带有滚动视图的 PageView 。
PageView 水平滚动。
滚动视图(子视图)垂直滚动。
预期结果
水平滑动和垂直滚动平滑。
实际结果
如果我水平滑动到下一页,我无法立即垂直滚动它。
我需要等待 1 秒。
看来用户必须等待动画完成才能与新的当前页面进行交互。
到目前为止我尝试了什么:
- 我试过手势识别器来传递拖动事件,但没有成功。
- 我尝试了不同的小部件来替换 PageView 但效果相同。
- 我尝试使用 wantKeepAlive = true 的 AutomaticKeepAliveClientMixin
- 我试过了 PageView.physics = AlwaysScrollableScrollPhysics()
这是重现问题所需的最少代码
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: carousel(),
);
}
Widget carousel() {
return PageView(
children: <Widget>[
page(Colors.pinkAccent),
page(Colors.blueAccent),
page(Colors.orangeAccent)
],
);
}
Widget page(Color color) {
return Container(
decoration: BoxDecoration(
color: color,
),
child: SingleChildScrollView(
child: Column(
children: pageContent()),
));
}
List<Widget> pageContent() {
return <Widget>[
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
];
}
}
经过一番挖掘,我认为问题出在 PageView 的 DragStartBehavior 上。本想流畅,PageView 的默认行为最终感觉迟钝,页面快照几乎感觉像是喝了太多酒。
这意味着当您想要垂直滚动时,PageView 仍然在变化中含糊不清。
在您调用 PageView 时调整 DragStartBehavior,它会感觉更有反应性 - 它会感觉更活泼,我相信这可能会解决您的问题。
Widget carousel() {
return PageView(
children: <Widget>[
dragStartBehavior: DragStartBehavior.down,
page(Colors.pinkAccent),
page(Colors.blueAccent),
page(Colors.orangeAccent)
],
);
}
p.s 谢谢 Yunnosch 的批评和笑:) 也请随意编辑,因为我还不能准确评论!
我成功找到了使我的 PageView 在水平和垂直方向上真正平滑的解决方案。
我禁用PageView.pageSnapping以使轮播非常流畅。
但是我失去了磁性效果,所以我使用 NotificationListener 来捕获 ScrollEndNotification 事件。
当滚动结束时,我计算出对用户最可见的页面并调用 PageController.animateToPage() 来完成工作。
代码如下所示:
Widget getCarousel() {
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification) {
print("ScrollEndNotification");
Future.delayed(const Duration(milliseconds: 0), () {
int newPage = pageController.page.round();
print("end at $newPage");
pageController.animateToPage(newPage, duration: Duration(milliseconds: 400), curve: Curves.fastOutSlowIn);
});
}
return true;
},
child: PageView.builder(
scrollDirection: Axis.horizontal,
pageSnapping: false,
controller: pageController,
itemBuilder: (BuildContext context, int index) {
return myPages[index];
},
)
);
}
- 我的问题总结
目标
我的目标是展示长页面的轮播。 所以我使用带有滚动视图的 PageView 。 PageView 水平滚动。 滚动视图(子视图)垂直滚动。
预期结果
水平滑动和垂直滚动平滑。
实际结果
如果我水平滑动到下一页,我无法立即垂直滚动它。 我需要等待 1 秒。 看来用户必须等待动画完成才能与新的当前页面进行交互。
到目前为止我尝试了什么:
- 我试过手势识别器来传递拖动事件,但没有成功。
- 我尝试了不同的小部件来替换 PageView 但效果相同。
- 我尝试使用 wantKeepAlive = true 的 AutomaticKeepAliveClientMixin
- 我试过了 PageView.physics = AlwaysScrollableScrollPhysics()
这是重现问题所需的最少代码
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: carousel(),
);
}
Widget carousel() {
return PageView(
children: <Widget>[
page(Colors.pinkAccent),
page(Colors.blueAccent),
page(Colors.orangeAccent)
],
);
}
Widget page(Color color) {
return Container(
decoration: BoxDecoration(
color: color,
),
child: SingleChildScrollView(
child: Column(
children: pageContent()),
));
}
List<Widget> pageContent() {
return <Widget>[
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
Row(children: <Widget>[Text("Hop", textScaleFactor: 5,)]),
];
}
}
经过一番挖掘,我认为问题出在 PageView 的 DragStartBehavior 上。本想流畅,PageView 的默认行为最终感觉迟钝,页面快照几乎感觉像是喝了太多酒。
这意味着当您想要垂直滚动时,PageView 仍然在变化中含糊不清。
在您调用 PageView 时调整 DragStartBehavior,它会感觉更有反应性 - 它会感觉更活泼,我相信这可能会解决您的问题。
Widget carousel() {
return PageView(
children: <Widget>[
dragStartBehavior: DragStartBehavior.down,
page(Colors.pinkAccent),
page(Colors.blueAccent),
page(Colors.orangeAccent)
],
);
}
p.s 谢谢 Yunnosch 的批评和笑:) 也请随意编辑,因为我还不能准确评论!
我成功找到了使我的 PageView 在水平和垂直方向上真正平滑的解决方案。
我禁用PageView.pageSnapping以使轮播非常流畅。 但是我失去了磁性效果,所以我使用 NotificationListener 来捕获 ScrollEndNotification 事件。 当滚动结束时,我计算出对用户最可见的页面并调用 PageController.animateToPage() 来完成工作。
代码如下所示:
Widget getCarousel() {
return NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification) {
print("ScrollEndNotification");
Future.delayed(const Duration(milliseconds: 0), () {
int newPage = pageController.page.round();
print("end at $newPage");
pageController.animateToPage(newPage, duration: Duration(milliseconds: 400), curve: Curves.fastOutSlowIn);
});
}
return true;
},
child: PageView.builder(
scrollDirection: Axis.horizontal,
pageSnapping: false,
controller: pageController,
itemBuilder: (BuildContext context, int index) {
return myPages[index];
},
)
);
}