Flutter作为一个UI框架,本身也有自己的事件处理方式,本文主要阐述触摸事件从native传递到Flutter后是如何被widget识别以及分发的。至于native系统是如何监听触摸事件以及传递事件到Flutter,感兴趣的可以自己去了解下不同的宿主系统处理的方式也是不同的。
事件处理流程
Flutter中对触摸事件的处理大致可以分为以下几个阶段:
- 监听事件的到来
- 对widget是否能响应事件进行命中测试
- 将事件分发给通过命中测试的widget
后续将触摸事件直接称为event
监听事件
event是由native系统通过消息通道传递到Flutter中的,因此Flutter必然会有对应的监听方法或者回调,从Flutter启动流程的源码中可以在mixin GestureBinding查看到下面代码:
@override
void initInstances() {
super.initInstances();
_instance = this;
window.onPointerDataPacket = _handlePointerDataPacket;
}
其中window.onPointerDataPacket正是监听event的回调,window是 Flutter 连接宿主操作系统的接口,其中包含了当前设备和系统的一些信息以及Flutter Engine的一些回调,下面展示了其部分属性。其他属性可以自行查看官方文档,注意这里的window不是dart:html标准库里window 类。
class Window {
// 当前设备的DPI,即一个逻辑像素显示多少物理像素,数字越大,显示效果就越精细保真。
// DPI是设备屏幕的固件属性,如Nexus 6的屏幕DPI为3.5
double get devicePixelRatio => _devicePixelRatio;
// Flutter UI绘制区域的大小
Size get physicalSize => _physicalSize;
// 当前系统默认的语言Locale
Locale get locale;
// 当前系统字体缩放比例。
double get textScaleFactor => _textScaleFactor;
// 当绘制区域大小改变回调
VoidCallback get onMetricsChanged => _onMetricsChanged;
// Locale发生变化回调
VoidCallback get onLocaleChanged => _onLocaleChanged;
// 系统字体缩放变化回调
VoidCallback get onTextScaleFactorChanged => _onTextScaleFactorChanged;
// 绘制前回调,一般会受显示器的垂直同步信号VSync驱动,当屏幕刷新时就会被调用
FrameCallback get onBeginFrame => _onBeginFrame;
// 绘制回调
VoidCallback get onDrawFrame => _onDrawFrame;
// 点击或指针事件回调
PointerDataPacketCallback get onPointerDataPacket => _onPointerDataPacket;
// 调度Frame,该方法执行后,onBeginFrame和onDrawFrame将紧接着会在合适时机被调用,
// 此方法会直接调用Flutter engine的Window_scheduleFrame方法
void scheduleFrame() native 'Window_scheduleFrame';
// 更新应用在GPU上的渲染,此方法会直接调用Flutter engine的Window_render方法
void render(Scene scene) native 'Window_render';
// 发送平台消息
void sendPlatformMessage(String name,
ByteData data,
PlatformMessageResponseCallback callback) ;
// 平台通道消息处理回调
PlatformMessageCallback get onPlatformMessage => _onPlatformMessage;
... //其它属性及回调
}
现在我们有了event在Flutter端的入口函数_handlePointerDataPacket,通过这个函数我们可以查看Flutter接收到event后是如何操作的,比较简单我们直接看下代码。
_handlePointerDataPacket
将event做一次转换,然后添加到一个队列中
///_pendingPointerEvents: Queue<PointerEvent>类型的队列
///locked: 通过标记位来实现的一个锁
void _handlePointerDataPacket(ui.PointerDataPacket packet) {
// We convert pointer data to logical pixels so that e.g. the touch slop can be
// defined in a device-independent manner.
_pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, window.devicePixelRatio));
if (!locked)
_flushPointerEventQueue();
}
_flushPointerEventQueue
遍历上面的队列,locked可以理

本文深入解析Flutter中触摸事件的处理流程,从事件监听、命中测试到事件分发,详细介绍了从native传递到Flutter的事件如何在widget层级中被识别和分发。特别关注了命中测试阶段,分析了RenderObject的hitTest方法以及在不同widget中的应用,揭示了事件分发的顺序和机制。
最低0.47元/天 解锁文章
593

被折叠的 条评论
为什么被折叠?



