(1)在移动端,各个平台或UI系统的原始指针事件模型基本都是一致,即:一次完整的事件分为三个阶段:手指按下、手指移动、和手指抬起,而更高级别的手势(如点击、双击、拖动等)都是基于这些原始事件的。
当指针按下时,Flutter会对应用程序执行命中测试(Hit Test),以确定指针与屏幕接触的位置存在哪些widget。注意,只有通过命中测试的Widget才能触发事件。
(2)Flutter中可以使用Listener widget来监听原始触摸事件,它也是一个功能性widget。
Listener({
Key key,
this.onPointerDown, //手指按下回调
this.onPointerMove, //手指移动回调
this.onPointerUp,//手指抬起回调
this.onPointerCancel,//触摸事件取消回调
this.behavior = HitTestBehavior.deferToChild, //在命中测试期间如何表现
Widget child
})
(3)说说Listener behavior:
Widget getBody() {
return Container(
child: Listener(
child: ConstrainedBox(
constraints: BoxConstraints.tight(Size(double.infinity, double.infinity)),
child: Center(child: Text("Box A")),
),
//behavior: HitTestBehavior.opaque,
onPointerDown: (event) => print("down A")
),
);
}
说明:
(a)注释掉上面behavior时,只有点击Text("Box A")时,才会打印down A;点击Text之外区域不会打印down A。
(b)当将behavior设置为opaque时,点击Text之外区域也会打印down A。
(c)opaque是不透明、模糊的意思。
(d)在命中测试的时候,将behavior设置为opaque,相当于当前Widget的整个区域都是点击区域。不然会按照deferToChild去子widget判断是否命中测试,而该例中子widget就是 Text("Box A") 。
(e)若将behavior设置为deferToChild时,子widget会一个接一个的进行命中测试,如果子Widget中有测试通过的,则当前Widget通过,这就意味着,如果指针事件作用于子Widget上时,其父(祖先)Widget也肯定可以收到该事件。
(4)忽略PointerEvent
假如我们不想让某个子树响应PointerEvent的话,我们可以使用IgnorePointer和AbsorbPointer,这两个Widget都能阻止子树接收指针事件,不同之处在于AbsorbPointer本身会参与命中测试,而IgnorePointer本身不会参与,这就意味着AbsorbPointer本身是可以接收指针事件的(但其子树不行),而IgnorePointer不可以。
Widget getBody() {
return Container(
child: Listener(
child: AbsorbPointer(
child: Listener(
child: Container(
color: Colors.green,
),
onPointerDown: (event)=>print("in"),
),
),
onPointerDown: (event)=>print("up"),
),
);
}
说明:
(a)上面代码点击只会输出up。这是因为AbsorbPointer自己会进行命中测试,而子widget会被阻止。
(b)将AbsorbPointer改为IgnorePointer时,则什么都不会输出。
(c)将AbsorbPointer改为Container时,则先输出in,后输出up。

本文详细介绍了Flutter中的原始指针事件处理,包括事件的三个阶段、Listener widget的使用以及PointerEvent的行为设置。重点讨论了behavior参数对命中测试的影响,如何设置使整个Widget区域成为点击区域,并探讨了如何通过IgnorePointer和AbsorbPointer控制子树对PointerEvent的响应。
1436

被折叠的 条评论
为什么被折叠?



