我们目前正在Flutter中构建一个应用程序,该应用程序具有可以在其中滑动的一系列页面,并且在每个页面内部我们都有一个水平滚动。
我们希望这样做,以便一旦到达水平滚动的末尾,就可以通过在水平滚动内部进一步滚动来滚动/滑动到下一页。
以下是展示所需行为的视频: https://vimeo.com/358643279
我们当前的实现存在问题,如下所示。
它在每页中都包含一个PageView
,在每页中我们都包含一个ListView
用于水平滚动。
一旦我们到达水平滚动的末尾,就不允许您进一步滚动滚动到下一页。
要滚动到下一页,必须在水平滚动之外做出滚动手势才能注册,这是不理想的。
这是一个最小的示例,您应该可以复制和粘贴。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ScrollingDemo',
home: PageView(scrollDirection: Axis.horizontal, children: [
Page(title: "Page 1"),
Page(title: "Page 2")
]));
}
}
class Page extends StatelessWidget {
Page({@required this.title});
final String title;
@override
Widget build(BuildContext context) {
final listView = ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
_buildContainer(1),
_buildContainer(2),
_buildContainer(3),
_buildContainer(4),
_buildContainer(5)
],
);
return Column(
children: [
Text(title),
Container(height: 200, width: 500, child: listView)
],
);
}
Container _buildContainer(int index) {
return Container(
color: Colors.green,
width: 250,
height: 250,
child: Center(child: Text(index.toString())),
);
}
}
非常感谢!
答案 0 :(得分:0)
您的问题归因于滚动的工作方式。您有两个水平滚动小部件,一个在另一个顶部(ListView在PageView顶部),因此ListView阻止滚动效果到达PageView。您可以使用ScrollController
和PageController
解决此问题。将单独的ScrollController添加到ListView中,并在这些控制器中侦听滚动事件,然后在PageView上相应地设置PageController的页面。
_scrollListener() async {
ScrollPosition position = _controller.position;
if (_controller.offset == position.maxScrollExtent) {
widget.pageController.nextPage(duration: Duration(milliseconds: 100), curve: Curves.linear);
} else if (_controller.offset == position.minScrollExtent) {
widget.pageController.previousPage(duration: Duration(milliseconds: 100), curve: Curves.linear);
}
}
请注意,您也必须切换到StatefulWidget Page类以实现此目的,但这非常简单。这段代码可以解决这个问题:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
final PageController _pageController = PageController();
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ScrollingDemo',
home: PageView(controller: _pageController, scrollDirection: Axis.horizontal, children: [
Page(
title: "Page 1",
pageController: _pageController,
),
Page(title: "Page 2", pageController: _pageController)
]));
}
}
class Page extends StatefulWidget {
final PageController pageController;
final String title;
Page({@required this.title, @required this.pageController});
@override
PageState createState() {
return PageState();
}
}
class PageState extends State<Page> {
final ScrollController _controller = ScrollController();
@override
void initState() {
super.initState();
_controller.addListener(_scrollListener);
}
_scrollListener() async {
ScrollPosition position = _controller.position;
if (_controller.offset == position.maxScrollExtent) {
widget.pageController.nextPage(duration: Duration(milliseconds: 100), curve: Curves.linear);
} else if (_controller.offset == position.minScrollExtent) {
widget.pageController.previousPage(duration: Duration(milliseconds: 100), curve: Curves.linear);
}
}
@override
Widget build(BuildContext context) {
final listView = ListView(
controller: _controller,
scrollDirection: Axis.horizontal,
children: <Widget>[_buildContainer(1), _buildContainer(2), _buildContainer(3), _buildContainer(4), _buildContainer(5)],
);
return Column(
children: [Text(widget.title), Container(height: 200, width: 500, child: listView)],
);
}
Container _buildContainer(int index) {
return Container(
color: Colors.green,
width: 250,
height: 250,
child: Center(child: Text(index.toString())),
);
}
}