在日常开发中,手势和事件无处不在,比如在 Flutter 应用中点击一个点赞按钮,长按弹出 BottomSheet 和商品列表的滑动等等都存在事件传递和手势识别,Flutter 内部是如何确定哪个控件响应了事件,事件是如何在控件之间传递的,包括像 Tap 和 DoubleTap 等手势是如何区分的。为了回答以上的问题,我们接下来深入探索 Flutter 手势的原理。
手势原理
事件分发
Flutter 中的事件是从 Window.onPointerDataPacket 的回调中获取的,将原始事件转化成 PointerEvent 加入到待处理的事件队列中,然后逐个处理队列中的 PointerEvent。
其中 _handlePointerEvent 将生成 HitTestResult 将所有的命中测试结果存在 _path (HitTestResult 中的一个命中测试对象的集合),最后遍历 HitTestResult 的 _path 进行事件分发。
命中测试
那么 HitTestResult 是如何收集这些命中测试结果的呢,与 Native 的 HitTest 类似,Flutter 中也是不断在遍历(调用 HitTest)child 判断 point 和 child 的大小比较直到找到最深一个 child 也就是离我们最近的一个 RenderBox。如果把 Widget 的结构理解成树的结构,那么 _path 中 entry 的顺序正好是从叶子节点往根节点回溯的顺序。