注册

Flutter事件之GestureBinding

Flutter在启动时(runApp)会进行一些浇水类的"粘合",WidgetsFlutterBinding作为主类,需要粘合一系列的Binding,其中GestureBinding就是事件处理类;


GestureBinding是Flutter中管理手势事件的Binding,是Flutter Framework层处理事件的最起点;


GestureBinding实现了HitTestable, HitTestDispatcher, HitTestTarget,分别具有以下功能



  • hitTest命中测试
  • dispatchEvent事件分发
  • handleEvent处理事件()

成员变量:


//触点路由,由手势识别器注册,会把手势识别器的pointer和handleEvent存入
//以便在GestureBinding.handleEvent调用
final PointerRouter pointerRouter = PointerRouter();

//手势竞技场管理者,管理竞技场们的相关操作
final GestureArenaManager gestureArena = GestureArenaManager();

//hitTest列表,里面存储了被命中测试成员
final Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};

GestureBinding在_handlePointerDataPacket方法接收有Engine层传递过来的触点数据,经过数据包装转换为Framework层可处理的数据:PointerAddedEvent、PointerCancelEvent、PointerDownEvent、PointerMoveEvent、PointerUpEvent等等,随后在_handlePointerEventImmediately方法中进行命中测试和事件分发;


手指按下


当手指按下时,接收到的事件类型是PointerDownEvent


首先是命中测试


当事件类型是event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent会进行新的命中测试,命中测试相关请看,得到命中测试列表后,开始调用dispatchEvent进行事件分发。


void _handlePointerEventImmediately(PointerEvent event) {
HitTestResult? hitTestResult;
if (event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent) {
assert(!_hitTests.containsKey(event.pointer));
hitTestResult = HitTestResult();
hitTest(hitTestResult, event.position);
if (event is PointerDownEvent) {
_hitTests[event.pointer] = hitTestResult;
}
assert(() {
if (debugPrintHitTestResults)
debugPrint('$event: $hitTestResult');
return true;
}());
} else if (event is PointerUpEvent || event is PointerCancelEvent) {
hitTestResult = _hitTests.remove(event.pointer);
} else if (event.down) {
//当前事件是按下状态,重用hitTest结果
hitTestResult = _hitTests[event.pointer];
}
if (hitTestResult != null ||
event is PointerAddedEvent ||
event is PointerRemovedEvent) {
assert(event.position != null);
dispatchEvent(event, hitTestResult);
}
}

事件分发


事件分发的目的是调用命中对象的handleEvent方法以处理相关逻辑,比如我们熟知的Listener组件,它做的事就是回调相关方法,比如按下时Listener会回调onPointerDown


## GestureBinding ##
@override // from HitTestDispatcher
void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) {
assert(!locked);
if (hitTestResult == null) {
assert(event is PointerAddedEvent || event is PointerRemovedEvent);
try {
pointerRouter.route(event);
} catch (exception, stack) {
...
}
return;
}
for (final HitTestEntry entry in hitTestResult.path) {
try {
entry.target.handleEvent(event.transformed(entry.transform), entry);
} catch (exception, stack) {
...
}
}
}

## Listener ##
@override
void handleEvent(PointerEvent event, HitTestEntry entry) {
assert(debugHandleEvent(event, entry));
if (event is PointerDownEvent)
return onPointerDown?.call(event);
if (event is PointerMoveEvent)
return onPointerMove?.call(event);
if (event is PointerUpEvent)
return onPointerUp?.call(event);
if (event is PointerHoverEvent)
return onPointerHover?.call(event);
if (event is PointerCancelEvent)
return onPointerCancel?.call(event);
if (event is PointerSignalEvent)
return onPointerSignal?.call(event);
}

我们知道命中测试最后会把GestrueBinding本身加入到列表中,所以最后也会执行GestrueBinding的handleEvent方法


handleEvent


GestrueBinding.handleEvent是处理手势识别器相关的逻辑,pointerRouter.route(event)调用了识别器的handleEvent方法(需要提前进行触点注册),随后的是竞技场的相关处理;可以看这里了解手势识别器;


## GestrueBinding ##
@override // from HitTestTarget
void handleEvent(PointerEvent event, HitTestEntry entry) {
pointerRouter.route(event);

if (event is PointerDownEvent) {
gestureArena.close(event.pointer);
} else if (event is PointerUpEvent) {
gestureArena.sweep(event.pointer);
} else if (event is PointerSignalEvent) {
pointerSignalResolver.resolve(event);
}
}

手指抬起,


手指抬起会重用之前hitTest结果,并不会重新hitTest,如果是Listener组件,则会回调PointerUpEvent


作者:palpitation97
链接:https://juejin.cn/post/7087873740658180133
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册