在学习flutter
的时候突然想到,flutter
既然不像其他跨平台框架那样采用系统原生渲染,那么flutter
就应该拥有自己的事件处理机制。本着好奇的心理,来对flutter
的事件处理机制一窥究竟。
1、flutter事件传递
事件都是由硬件收集起来的,然后传递给软件。那么在flutter
中,事件的源头在哪尼?
经过分析源码可以发现。在类window
中,flutter
通过方法onPointerDataPacket
来接收硬件传递过来的事件,也就是说该方法是flutter
接收事件的源头,而该方法是在类GestureBinding
初始化的时候设置的。所以在类GestureBinding
的方法_handlePointerDataPacket
中开始处理事件。
mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, HitTestTarget {
@override
void initInstances() {
super.initInstances();
_instance = this;
//_handlePointerDataPacket(是一个私有方法)接收系统传递过来的事件,
window.onPointerDataPacket = _handlePointerDataPacket;
}
...
//一个FIFO的双端队列,用来存储事件
final Queue<PointerEvent> _pendingPointerEvents = Queue<PointerEvent>();
void _handlePointerDataPacket(ui.PointerDataPacket packet) {
//这里做了以下两个操作
//1、将pointer数据转换为逻辑像素,从而隔离真实设备。
//2、将转换后的数据加入到FIFO双端队列中
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, window.devicePixelRatio));
if (!locked){
//开始处理事件
_flushPointerEventQueue();
}
}
...
void _flushPointerEventQueue() {
assert(!locked);
//如果队列中有数据,就处理
while (_pendingPointerEvents.isNotEmpty)
_handlePointerEvent(_pendingPointerEvents.removeFirst());
}
...
final Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};
void _handlePointerEvent(PointerEvent event) {
assert(!locked);
HitTestResult hitTestResult;
//如果是Down事件
if (event is PointerDownEvent) {
assert(!_hitTests.containsKey(event.pointer));
hitTestResult = HitTestResult();
//将事件要经过的所有Widget添加到一个集合中
hitTest(hitTestResult, event.position);
_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) {
//如果是move事件
hitTestResult = _hitTests[event.pointer];
}
assert(() {
if (debugPrintMouseHoverEvents && event is PointerHoverEvent)
debugPrint('$event');
return true;
}());
if (hitTestResult != null ||
event is PointerHoverEvent ||
event is PointerAddedEvent ||
event is PointerRemovedEvent) {
//分发事件
dispatchEvent(event, hitTestResult);
}
}
@override // from HitTestable
void hitTest(HitTestResult result, Offset position) {
result.add(HitTestEntry(this));
}
//事件的分发
@override // from HitTestDispatcher
void dispatchEvent(PointerEvent event, HitTestResult hitTestResult) {
assert(!locked);
...
for (HitTestEntry entry in hitTestResult.path) {
try {
//分发给子Widget处理
entry.target.handleEvent(event, entry);
} catch (exception, stack) {
...
}
}
}
//
@override // from HitTestTarget
void handleEvent(PointerEvent event, HitTestEntry entry) {
pointerRouter.route(event);
if (event is PointerDownEvent) {
gestureArena.close(event.pointer);
} else if (event