如果可以模拟 PointerEvent 进行分发,那么在应用中就可以通过代码来触发手势事件,这样就能解放双手。如果结合语音监听,通过代码处理,说话也能触发手势操作,岂不美哉。
作为探索完手势机制和滑动机制,又有完成这两本小册的我,感觉这个问题应该可解。下面就将整个问题的解决过程进行梳理,带大家再认识一下手势底层的相关实现。
2. 自己分发事件然后想到手势事件分发是由 GestureBinding 处理的,而我们可以通过 GestureBinding.instance 获取 GestureBinding 对象。那是不是意味着,可以自己来分发一个 PointerDownEvent 的消息。于是创建如下示例界面: 上部有两个按钮分别用于模拟滑动和模拟点击。
所以现在的问题是,如果我们无法创建 HitTestResult,就无法通过 dispatchEvent 方法来分发 PointerDownEvent 事件。但 HitTestResult 是从 hitTest 收集的,我们似乎很难去主动创建,似乎问题进入了死胡同。
二、单击事件是如何触发的
1. 回顾单击事件的触发
如下是点击加好按钮时 FloatingActionButton#onPressed 回调触发的方法栈情况,可以看到是在分发 PointerUpEvent 类型事件下触发单击事件的:
三、模拟事件触发的实现
如下效果所示: 通过模拟点击可以点击右下角的加号按钮,从而让上面黄色区域内的数字自加;通过模拟滑动让列表滑动。这样我们就实现了通过代码来触发手势事件.
1.void _pressAdd() {
2.const PointerEvent addPointer = PointerAddedEvent(
3. pointer: 0,
4. position: Offset(322.8, 746.9)
5. );
6.const PointerEvent downPointer = PointerDownEvent(
7. pointer: 0,
8.position: Offset(322.8, 746.9)
9. );
10.const PointerEvent upPointer = PointerUpEvent(
11.pointer: 0,
12. position: Offset(322.8, 746.9)
13. );
14. GestureBinding.instance!.handlePointerEvent(addPointer);
15. GestureBinding.instance!.handlePointerEvent(downPointer);
16.GestureBinding.instance!.handlePointerEvent(upPointer); 17.
}
如下,滑动事件的触发关键点在于 tag1 处,通过 for 循环模拟 20 次偏移量是 20 的向上滑动事件。
void _pressMove() async {
2.const PointerEvent addPointer = PointerAddedEvent(
3. pointer: 1,
4. position: Offset(122.8, 746.9)
5. );
6.const PointerEvent downPointer = PointerDownEvent(
7. pointer: 1,
8. position: Offset(122.8, 746.9)
9. );
10. GestureBinding.instance!.handlePointerEvent(addPointer);
11. GestureBinding.instance!.handlePointerEvent(downPointer);
12.
13.double dy = 20;
14. double updateCount = 20;
15. for (int i = 0; i < 20; i++) { // tag1
16. await Future.delayed(const Duration(milliseconds: 6));
17. PointerEvent movePointer = PointerMoveEvent(
18. pointer: 1,
19.delta: Offset(0, -dy),
20. position: Offset(122.8, 746.9 - i * dy)
21.);
22. GestureBinding.instance!.handlePointerEvent(movePointer);
23. }
24.
25.PointerEvent upPointer = PointerUpEvent(
26. pointer: 1,
27. position: Offset(122.8, 746.9 - dy * updateCount)
28. );
29. GestureBinding.instance!.handlePointerEvent(upPointer);
30.
}
对于一些流程性的测试,或精准的滑动控制分析,用代码模拟会显得更加重要,因为一些性能分析需要控制变量,手动滑动多多少少会有不同,从而影响测试分析的结果。本篇就到这里,希望通过本文您能对 Flutter 的手势有更深切的认识,也希望 Flutter 模拟事件触发,在某个时刻可以帮助到您。