Flutter事件响应源码分析

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

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可以理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值