美文网首页
Flutter事件处理

Flutter事件处理

作者: 旺仔_100 | 来源:发表于2023-04-16 09:55 被阅读0次
一、Flutter事件原理介绍

在移动端,一次完整的时间分为三个阶段:手指按下,手指移动,和手指抬起,而更高级的手势(如点击、双击、拖动等)都是基于这些原始事件。

当手指按下的时候,Flutter会对应用程序执行命中测试(Hit Test),以确定手指与屏幕接触的位置存在哪些组件(widget),手指按下事件(以及该指针的后续事件)然后被分发到由命中测试发现的最内部的组件,然后从那里开始,事件会在组件树向上冒泡,这些事件会从最内部的组件被分发到组件树根路径上的所有组件。只有通过命中测试的组件才能触发事件

Flutter中可以使用Listener来监听原始触摸事件,Listener的构造如下:

 const Listener({
    Key? key,
    this.onPointerDown,//手指按下回调
    this.onPointerMove, //手指移动回调
    this.onPointerUp,//手指抬起回调
    this.onPointerHover,
    this.onPointerCancel,//触摸事件取消回调
    this.onPointerSignal,
    this.behavior = HitTestBehavior.deferToChild,
    Widget? child,
  })

PointerDownEvent、 PointerMoveEvent、 PointerUpEvent 都是PointerEvent的子类,PointerEvent类中包括当前手指的一些信息。

position:它是指针相对于当对于全局坐标的偏移。
localPosition: 它是指针相对于当对于全局坐标的偏移
delta:两次指针移动事件(PointerMoveEvent)的距离。
pressure:按压力度,如果手机屏幕支持压力传感器(如iPhone的3D Touch),此属性会更有意义,如果手机不支持,则始终为1。
orientation:指针移动方向,是一个角度值。

Flutter中封装了GestureDetetor和GestureRecognizer识别和处理手势冲突,具体使用并不难,可以自己去学习。

二、Flutter 事件处理流程

Flutter 事件处理流程主要分为两步,为了聚焦核心流程,我们以用户触摸事件为列:
1.命中测试:当手指按下时,触发PointDownEvent事件,按照深度优先遍历当前渲染树,对每一个渲染对象进行命中测试(hit test),如果命中测试通过,则该渲染对象会被添加到一个HitTestResult列表中。
2.事件分发:命中测试完毕后,会遍历HitTestResult列表,调用每一个渲染对象的事件处理方法(handleEvent)来处理PointerDownEvent事件,改过程为"事件分发"(event dispatch)。随后当手指移动的时,便会分发PointerMoveEvent事件。
3.事件清洗:当手指抬起(PointerUpEvent)或事件取消时(PointerCancelEvent),会先对响应的事件分发,分发完毕后会清空HitTestResult列表。

可以从源码的层面来看整个事件处理流程

// 触发新事件时,flutter 会调用此方法
void _handlePointerEventImmediately(PointerEvent event) {
  HitTestResult? hitTestResult;
  if (event is PointerDownEvent ) {
    hitTestResult = HitTestResult();
    // 发起命中测试
    hitTest(hitTestResult, event.position);
    if (event is PointerDownEvent) {
      _hitTests[event.pointer] = hitTestResult;
    }
  } else if (event is PointerUpEvent || event is PointerCancelEvent) {
    //获取命中测试的结果,然后移除它
    hitTestResult = _hitTests.remove(event.pointer);
  } else if (event.down) { // PointerMoveEvent
    //直接获取命中测试的结果
    hitTestResult = _hitTests[event.pointer];
  }
  // 事件分发
  if (hitTestResult != null) {
    dispatchEvent(event, hitTestResult);
  }
}
三、命中测试

一个对象是否可以响应事件,取决于在其对命中测试过程中是否被添加到了HitTestResult列表,如果没有被添加进去,则后续的时间分发将不会分发给自己。命中测试分两步:
1.renderView是RenderView对应的RenderObject对象,RederObject对象的hitTest方法主要功能是:从该节点出发,按照深度优先的顺序递归遍历子树(渲染树)上的每一个节点并对他进行命中测试。这个过程称为“渲染树命中测试”。
2.渲染树命中测试完毕后,会调用GestureBinding的HitTest方法,该方法主要用于处理手势,我们会在后面介绍。

总结原理

会按照rederObjective树的去深度遍历每个子节点,如果hittest返回true,就是命中测试了,会终止遍历。然后会把从他开始的向上到定点的节点都添加到HitResult里面。然后会遍历HitResult执行他们的handleEvent来处理事件。只有Listener和他的一些子类会执行handleEvent。

相关文章

网友评论

      本文标题:Flutter事件处理

      本文链接:https://www.haomeiwen.com/subject/bmdehrtx.html