一个能识别手势的 widget。相比于 Listener,GestureDetector,更加常用。
GestureDetector 介绍
GestureDetector 就不分析源码了,有兴趣的同学可以读下这篇 从源码看flutter(五):GestureDetector篇。简单的介绍下,GestureDetector 是一个 StateFulWidget,内部调用 RawGestureDetector,RawGestureDetector 又调用 Listener 监听 onPointerDown 和 onPointerPanZoomStart 事件。GestureDetector 作用仅是简化 RawGestureDetector 的使用。作为平时使用 GestureDetector 的功能就足够了。哪天如果不能满足的时候,再去找 RawGestureDetector。
使用 GestureDetector
GestureDetector 使用了很多手势识别器,最常用的就是 TapGestureRecognizer 了,使用起来很简单。
GestureDetector(
onTap: () {
print('tap');
},
child: Container(
width: 100,
height: 100,
color: Colors.blue,
))
如果没有 child 要响应 pointer 事件,需要指定 behavior。
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
debugPrint('tap');
},
);
opaque 的含义在 Listener 中有讲。
其它手势也都一样,使用还是很简单的,真正需要我们关心的是手势冲突。
有多个手势竞争的时候,child 的手势会胜出
GestureDetector(
onTap: () {
debugPrint('tap parent');
},
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
debugPrint('tap child');
},
),
);
只输出 tap child。 当 parent 和 child 同时响应 onTap 时, child 胜出。当有多个手势参与竞争的时候,需要竞技场管理者进行裁决。当 pointer up 事件发出的时候,竞技场管理者判定第一个位置的 tap 手势选手胜出。在执行 hitTest 的时候,是深度优先,所以 child 会先加入 结果列表,位置一定在 parent 前面。
pointer move 事件会打断 tap
GestureDetector(
behavior: HitTestBehavior.opaque,
onHorizontalDragEnd: (details) {
debugPrint('darg end');
},
onTapDown: (details) {
debugPrint('tap down');
},
onTap: () {
debugPrint('tap');
},
);
如果有滑动手势胜出,输出 “tap down” 和 “move end”。
pointer down 后在一定时间内滑动超过一定距离,那么就会被判定为 PointerMoveEvent,tap 手势被移出竞技场。tapUp 和 tap 事件不会再响应。tapDown 会响应,因为 tapDown 在 pointerDownEvent 的时候就被裁决出来了。
同时存在 tap ,doubleTap
只有 tap 的时候,pointer up 的时候,立即执行,如果同时存在 double tap,需要等上 300ms,因为要判断是否要响应 double tap。tap ,doubleTap 只能有一个胜出。
同时存在 tap ,onLongPress
如果同时存在 tap,onLongPress,需要等上 500ms,因为要判断是否要响应 longPress。tap ,onLongPress 只能有一个胜出。
虽然只举这几个例子,但当多个手势竞争的时候必然会有冲突,解决冲突可以用 Listener 替代。