停止 Flutter Listener 小部件的事件冒泡

m93*_*93a 10 event-bubbling event-propagation flutter

我正在 Flutter 中制作一个 Android 应用程序,我想添加一个交互式小部件来侦听原始指针事件并对它们做出反应。使用小部件很容易做到这一点Listener

\n
class _MyWidget extends State<MyWidget> {\n  @override\n  build(BuildContext ctx) {\n    return Listener(\n      onPointerMove: (event) {\n        event.delta // use this to do some magic...\n      },\n      child: ...\n    );\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然而,这个小部件是在 a 内呈现的PageView,它允许用户滑动以更改页面。这是我不想摆脱 \xe2\x80\x93 的行为,除了用户滑过的时间MyWidget。由于MyWidget需要用户触摸并拖动,我不希望他们意外导航到不同的页面。

\n

在浏览器中,这实现起来非常简单,我只需调用event.stopPropagation(),事件就不会从其MyWidget祖先传播(即冒泡) PageView如何停止 Flutter 中事件的传播?

\n

理论上,我可以MyWidget设置应用程序状态,并PageView在我滑动时使用它来禁用MyWidget。然而,这将违背 Flutter 小部件的自然数据流:它需要我在多个位置添加回调,并使所有小部件更加交织在一起且可重用性降低。我更愿意防止事件在本地冒泡。

\n
\n

编辑:我尝试过使用AbsorbPointer,但它似乎在错误的方向上“阻止传播”。它阻止 的所有子级接收AbsorbPointer指针事件。我想要的是完全相反的 \xe2\x80\x93 阻止子级上的指针事件传播到其祖先。

\n

use*_*613 15

在 Flutter 中,通常只有 1 个 widget 响应用户触摸事件,而不是触摸位置处的所有部件一起响应。为了确定哪个小部件应该响应触摸事件,Flutter 使用一种称为“手势竞技场”的东西来确定“获胜者”。

Listener是一个原始的监听小部件,不会在“手势竞技场”中竞争,因此即使在技术上更接近用户(并且会获胜),底层PageView仍将在“手势竞技场”中“获胜” 。Listener

另一方面,更先进的(较少原始的)小部件,例如GestureDetector确实进入“手势竞技场”竞争,并且会“获胜”,从而导致PageView在竞技场中“失败”,因此页面视图不会移动。

例如,尝试将此代码放入 a 中PageView并拖动它:

GestureDetector(
  onHorizontalDragUpdate: (DragUpdateDetails details) {
    print('on Horizontal Drag Update');
  },
  onVerticalDragUpdate: (DragUpdateDetails details) {
    print('on Vertical Drag Update');
  },
  child: Container(
    width: 100,
    height: 100,
    color: Colors.red,
  ),
)
Run Code Online (Sandbox Code Playgroud)

您应该注意到PageView不再滚动。

但是,根据 的滚动轴PageView(无论是水平滚动还是垂直滚动),删除上面的事件之一GestureDetector(例如删除onHorizontalDragUpdate水平滚动的事件侦听器PageView)将使 能够PageView再次滚动。这是因为水平滑动和垂直滑动是进入不同手势区域的“非冲突事件”。

那么,回到你原来的问题,你可以使用这些“更高级”的小部件重写你的业务逻辑,而不是处理原始级别的数据吗Listener?如果是这样,框架就会为你解决问题。

Listener如果您出于某种原因必须使用,我为您提供了另一种可能的解决方法:在PageView小部件中,您可以传入physics: const NeverScrollableScrollPhysics()以使其停止滚动。因此,您也许可以监视触摸事件,并相应地设置/清除属性。本质上,在“触地”时,锁定PageView,在“触地”时释放它。