第1节:点击测试
1. 命中测试的起点
一个对象是否可以响应事件,取决于在其对命中测试过程中是否被添加到了 HitTestResult 列表 ,如果没有被添加进去,则后续的事件分发将不会分发给自己。下面我们看一下命中测试的过程:当发生用户事件时,Flutter 会从根节点(RenderView
)开始调用它hitTest()
@override
void hitTest(HitTestResult result, Offset position) {
//从根节点开始进行命中测试
renderView.hitTest(result, position: position);
// 会调用 GestureBinding 中的 hitTest()方法,我们将在下一节中介绍。
super.hitTest(result, position);
}
第一步: renderView 是 RenderView 对应的 RenderObject 对象, RenderObject 对象的 hitTest 方法主要功能是:从该节点出发,按照深度优先的顺序递归遍历子树(渲染树)上的每一个节点并对它们进行命中测试。这个过程称为“渲染树命中测试”。
第二步:渲染树命中测试完毕后,会调用 GestureBinding 的 hitTest 方法,该方法主要用于处理手势。
2.渲染树命中测试过程
渲染树的命中测试流程就是父节点 hitTest 方法中不断调用子节点 hitTest 方法的递归过程。下面是RenderView
的hitTest()
源码:
// 发起命中测试,position 为事件触发的坐标(如果有的话)。
bool hitTest(HitTestResult result, { Offset position }) {
if (child != null)
child.hitTest(result, position: position); //递归对子树进行命中测试
//根节点会始终被添加到HitTestResult列表中
result.add(HitTestEntry(this));
return true;
}
因为 RenderView 只有一个孩子,所以直接调用child.hitTest 即可。如果一个渲染对象有多个子节点,则命中测试逻辑为:如果任意一个子节点通过了命中测试或者当前节点“强行声明”自己通过了命中测试,则当前节点会通过命中测试。