如何处理 Flutter PageView 中的滚动视图手势?

How to handle scrollview gestures inside a Flutter PageView?

  1. 我的问题总结

目标

我的目标是展示长页面的轮播。 所以我使用带有滚动视图的 PageView 。 PageView 水平滚动。 滚动视图(子视图)垂直滚动。

预期结果

水平滑动和垂直滚动平滑。

实际结果

如果我水平滑动到下一页,我无法立即垂直滚动它。 我需要等待 1 秒。 看来用户必须等待动画完成才能与新的当前页面进行交互。

到目前为止我尝试了什么:

这是重现问题所需的最少代码

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];
    },
  )
);
}