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

时间:2020-04-29 21:01:18

标签: flutter scrollview gesture flutter-pageview

  1. 我的问题摘要

目标

我的目标是呈现一个长页面的轮播。 所以我使用带有滚动视图的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,)]),
    ];
  }
}

2 个答案:

答案 0 :(得分:0)

稍作挖掘后,我相信问题出在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的谴责和嘲笑:)也可以随意编辑此内容,因为我还不能发表评论!

答案 1 :(得分:0)

我成功地找到了一种解决方案,使我的 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];
    },
  )
);
}