停止从 Flutter Listener 小部件冒泡的事件
Stop event bubbling from Flutter Listener widget
我正在 Flutter 中制作一个 Android 应用程序,我想添加一个交互式小部件来侦听原始指针事件并对其做出反应。使用 Listener
小部件很容易做到这一点:
class _MyWidget extends State<MyWidget> {
@override
build(BuildContext ctx) {
return Listener(
onPointerMove: (event) {
event.delta // use this to do some magic...
},
child: ...
);
}
}
但是,此小部件在 PageView
内呈现,允许用户滑动以更改页面。这是我不想摆脱的行为 – 除了 用户滑动 MyWidget
的时间。由于 MyWidget
要求用户 touch-and-drag,我不希望他们不小心导航到不同的页面。
在浏览器中,这将非常容易实现,我只需调用 event.stopPropagation()
并且事件不会从 MyWidget
传播(即冒泡)到其祖先 PageView
。 如何在 Flutter 中停止传播事件?
我 可以 ,理论上,让 MyWidget
设置应用程序状态,并在我滑动 [=] 时使用它来禁用 PageView
13=]。然而,这将违背 Flutter 小部件的自然数据流:它需要我在多个地方添加回调,并使所有小部件更加交织在一起,并且可重用性降低。我更愿意阻止事件冒泡,locally.
编辑:我试过使用AbsorbPointer
,但它似乎在错误的方向“阻止传播”。它阻止 AbsorbPointer
的所有 children 接收指针事件。我想要的恰恰相反——阻止 child 上的指针事件传播到它的祖先。
在 Flutter 中,通常只有 1 个小部件会响应用户触摸事件,而不是触摸位置的所有部件都一起响应。为了确定哪个小部件应该响应触摸事件,Flutter 使用一种称为“手势竞技场”的东西来确定“赢家”。
Listener
是一个原始的监听小部件, 不会在“手势竞技场”中竞争,因此底层 PageView
仍将“获胜” “手势竞技场”,尽管 Listener
在技术上更接近用户(并且会赢)。
另一方面,GestureDetector
等更高级(较少原始)的小部件确实进入了“手势竞技场”竞争,并将“获胜”,从而导致 PageView
“失败” "在竞技场中,所以页面浏览量不会移动。
例如,尝试将此代码放在 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,
),
)
您应该注意到 PageView
不再滚动。
但是,根据 PageView
的滚动轴(无论是水平滚动还是垂直滚动),删除上面 GestureDetector
上的事件之一(例如删除 onHorizontalDragUpdate
事件侦听器在水平滚动 PageView
) 将使 PageView
再次滚动。这是因为水平滑动和垂直滑动是进入不同手势领域的“non-conflicting事件”。
那么,回到您最初的问题,您能否使用这些“更高级”的小部件来重写您的业务逻辑,而不是处理原始级别的数据 Listener
?如果是这样,问题将由框架为您解决。
如果您出于某种原因必须使用 Listener
,我为您提供了另一种可能的解决方法:在 PageView
小部件中,您可以传入 physics: const NeverScrollableScrollPhysics()
以使其停止滚动。因此,您也许可以监视触摸事件,并相应地 set/clear 属性 。本质上,在“touch down”时,锁定 PageView
,在“touch up”时,释放它。
我正在 Flutter 中制作一个 Android 应用程序,我想添加一个交互式小部件来侦听原始指针事件并对其做出反应。使用 Listener
小部件很容易做到这一点:
class _MyWidget extends State<MyWidget> {
@override
build(BuildContext ctx) {
return Listener(
onPointerMove: (event) {
event.delta // use this to do some magic...
},
child: ...
);
}
}
但是,此小部件在 PageView
内呈现,允许用户滑动以更改页面。这是我不想摆脱的行为 – 除了 用户滑动 MyWidget
的时间。由于 MyWidget
要求用户 touch-and-drag,我不希望他们不小心导航到不同的页面。
在浏览器中,这将非常容易实现,我只需调用 event.stopPropagation()
并且事件不会从 MyWidget
传播(即冒泡)到其祖先 PageView
。 如何在 Flutter 中停止传播事件?
我 可以 ,理论上,让 MyWidget
设置应用程序状态,并在我滑动 [=] 时使用它来禁用 PageView
13=]。然而,这将违背 Flutter 小部件的自然数据流:它需要我在多个地方添加回调,并使所有小部件更加交织在一起,并且可重用性降低。我更愿意阻止事件冒泡,locally.
编辑:我试过使用AbsorbPointer
,但它似乎在错误的方向“阻止传播”。它阻止 AbsorbPointer
的所有 children 接收指针事件。我想要的恰恰相反——阻止 child 上的指针事件传播到它的祖先。
在 Flutter 中,通常只有 1 个小部件会响应用户触摸事件,而不是触摸位置的所有部件都一起响应。为了确定哪个小部件应该响应触摸事件,Flutter 使用一种称为“手势竞技场”的东西来确定“赢家”。
Listener
是一个原始的监听小部件, 不会在“手势竞技场”中竞争,因此底层 PageView
仍将“获胜” “手势竞技场”,尽管 Listener
在技术上更接近用户(并且会赢)。
另一方面,GestureDetector
等更高级(较少原始)的小部件确实进入了“手势竞技场”竞争,并将“获胜”,从而导致 PageView
“失败” "在竞技场中,所以页面浏览量不会移动。
例如,尝试将此代码放在 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,
),
)
您应该注意到 PageView
不再滚动。
但是,根据 PageView
的滚动轴(无论是水平滚动还是垂直滚动),删除上面 GestureDetector
上的事件之一(例如删除 onHorizontalDragUpdate
事件侦听器在水平滚动 PageView
) 将使 PageView
再次滚动。这是因为水平滑动和垂直滑动是进入不同手势领域的“non-conflicting事件”。
那么,回到您最初的问题,您能否使用这些“更高级”的小部件来重写您的业务逻辑,而不是处理原始级别的数据 Listener
?如果是这样,问题将由框架为您解决。
如果您出于某种原因必须使用 Listener
,我为您提供了另一种可能的解决方法:在 PageView
小部件中,您可以传入 physics: const NeverScrollableScrollPhysics()
以使其停止滚动。因此,您也许可以监视触摸事件,并相应地 set/clear 属性 。本质上,在“touch down”时,锁定 PageView
,在“touch up”时,释放它。