Flutter runApp GestureBinding使用介绍

目录
  • GestureBinding介绍
  • methods
  • 总结

GestureBinding介绍

在上一篇文章《Flutter runApp到渲染上屏》中,我们介绍了从runApp直到渲染到屏幕上.为了整体流程顺畅因此一些内容没有花过多的文笔描述,所以本章节单独陈述GestureBinding这个mixin对象.

想去了解一个类最好的方法无外乎去阅读它的注释,我们可以从它的注释中去了解它是为了做什么,做了些什么, 能够做什么.

原文 汉译
A binding for the gesture subsystem.

## Lifecycle of pointer events and the gesture arena

### [PointerDownEvent]

When a [PointerDownEvent] is received by the [GestureBinding] (from [dart:ui.PlatformDispatcher.onPointerDataPacket], as interpreted by the [PointerEventConverter]), a [hitTest] is performed to determine which [HitTestTarget] nodes are affected. (Other bindings are expected to implement [hitTest] to defer to [HitTestable] objects. For example, the rendering layer defers to the [RenderView] and the rest of the render object hierarchy.)

The affected nodes then are given the event to handle ([dispatchEvent] calls [HitTestTarget.handleEvent] for each affected node). If any have relevant [GestureRecognizer]s, they provide the event to them using [GestureRecognizer.addPointer]. This typically causes the recognizer to register with the [PointerRouter] to receive notifications regarding the pointer in question.

Once the hit test and dispatching logic is complete, the event is then passed to the aforementioned [PointerRouter], which passes it to any objects that have registered interest in that event.

Finally, the [gestureArena] is closed for the given pointer ([GestureArenaManager.close]), which begins the process of selecting a gesture to win that pointer.

### Other events

A pointer that is [PointerEvent.down] may send further events, such as [PointerMoveEvent], [PointerUpEvent], or [PointerCancelEvent]. These are sent to the same [HitTestTarget] nodes as were found when the [PointerDownEvent] was received (even if they have since been disposed; it is the responsibility of those objects to be aware of that possibility).

Then, the events are routed to any still-registered entrants in the [PointerRouter]'s table for that pointer.

When a [PointerUpEvent] is received, the [GestureArenaManager.sweep] method is invoked to force the gesture arena logic to terminate if necessary.

手势子系统的绑定。

## 指针事件和手势竞技场的生命周期

### [PointerDownEvent]

当 [GestureBinding] 接收到 [PointerDownEvent](来自[dart:ui.PlatformDispatcher.onPointerDataPacket],由[PointerEventConverter]), 执行[hitTest]以确定哪个[HitTestTarget] 节点受到影响。 (其他Bindings预计实现 [hitTest] 以推迟到 [HitTestable] 对象。例如,渲染层遵从 [RenderView] 和渲染对象的其余部分。)

然后给受影响的节点处理事件([dispatchEvent] 调用每个受影响节点的 [HitTestTarget.handleEvent])。如有相关[GestureRecognizer]s,他们使用[GestureRecognizer.addPointer]。这通常会导致识别器向 [PointerRouter] 注册以接收有关有问题的指针。

一旦命中测试和调度逻辑完成,事件就会发生传递给前面提到的 [PointerRouter],它将它传递给任何对象已经注册了对该事件的兴趣。

最后,[gestureArena] 为给定的指针关闭([GestureArenaManager.close]),它开始选择一个赢得该指针的手势。

### 其他事件

[PointerEvent.down] 的指针可能会发送更多事件,例如[PointerMoveEvent]、[PointerUpEvent] 或 [PointerCancelEvent]。这些是发送到相同的 [HitTestTarget] 节点
[PointerDownEvent] 已收到(即使它们已被处置;它是这些对象有责任意识到这种可能性)。

然后,事件被路由到[PointerRouter] 的指针表。

当接收到 [PointerUpEvent] 时,[GestureArenaManager.sweep] 方法被调用以强制手势竞技场逻辑在必要时终止。

methods

了解完GestureBinding大致是做什么的, 我们再了解一下它有哪些方法.

其中initInstances()不知道大家有没有印象, 在BindingBase的构造方法中有调用这个方法, 那自然在初始的时候会调用这个方法.

{
    // 保存实例
    _instance = this;
    // 平台分发, 这里接受native传来的手势信息作分发
    platformDispatcher.onPointerDataPacket = _handlePointerDataPacket;
}

实际上也就是在开始的时候注册了手势的接收分发.那么手势是如何分发的呢?我们不如看一下_handlePointerDataPacket 的具体实现:

{
    // 这里会将指针数据转换为逻辑像素,同时保存
    _pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data,
    window.devicePixelRatio));
    // 首先,我们要了解下locked是从什么地方来的,
    // 可以看到它最终的改变地只有*lockEvents()*方法中,而*lockEvents()*方法
    // 由*reassembleApplication()*或scheduleWarmUpFrame()调用,
    // 前者属于例如热重载之类时调用, 而后者我们在runApp时也有过介绍.
    // 这里看起来更像是一个异步回调的锁.也就是在重启界面的时候不用去刷新指针队列
    if (!locked) _flushPointerEventQueue();
}

这里又引出来一个_flushPointerEventQueue()的概念,这里会真正的去分发手势事件:

{
    // 只有我们接收到了手势队列中还有对象就会持续运行
    while (_pendingPointerEvents.isNotEmpty){
        // 这里删除了第一个元素并返回第一个元素,也就是队列的fifo.
        // 我们会依次处理接受到的手势事件
        handlePointerEvent(_pendingPointerEvents.removeFirst());
    }
}

那么,*handlePointerEvent()*做了什么呢?

// 断言之类代码已经去掉
{
    // 如果这个开关打开,我们可以获取更平滑到手势事件,
    // 比如90hz、120hz的屏幕. 我们在一些界面处理上就可以打开这个开关,
    // 同样这个值也是可以动态开关的
    if (resamplingEnabled) {
        // 重采样这里不过多介绍,有兴趣可以自行探索一下哦!
        _resampler.addOrDispatch(event);
        _resampler.sample(samplingOffset, _samplingClock);
        return;
    }
    _resampler.stop();
    // 这里去处理指针事件,从名字上来看是非常迫切了,hhh
    _handlePointerEventImmediately(event);
}
// 这里会对每一个指针事件进行判断,是否点中widget或者说命中了哪个widget
{
    HitTestResult? hitTestResult;
    if (event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent) {
      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) {
      hitTestResult = _hitTests[event.pointer];
    }
    if (hitTestResult != null ||
        event is PointerAddedEvent ||
        event is PointerRemovedEvent) {
      dispatchEvent(event, hitTestResult);
    }
}

这里的代码比较简单, 如果事件是down、signal或者hover之中的任何事件,则会通过hitTest()添加到HitTestResult中,假如是down事件还需要增加到_hitTests结果中.如果是up或者cancel事件,那说明用户取消了当时到滑动事件,我们自然而然需要去除相应的事件.最后去分发手势.

  void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) {
    if (hitTestResult == null) {
      try {
        // 分发指针时, 会把所有通过条件的event都注册到手势路由里面
        pointerRouter.route(event);
      } catch (exception, stack) {
        ...
      }
      return;
    }
    for (final HitTestEntry entry in hitTestResult.path) {
      try {
        // 这里回调一下结果判断有没有命中
        entry.target.handleEvent(event.transformed(entry.transform), entry);
      } catch (exception, stack) {
        ...
      }
    }
  }

也就是到这里整体到流程就结束了.

总结

从源码开始带着思考去跟踪问题, 也许问题就很容易可以解决了.手势的流程也就是在这一刻注册的,

以上就是Flutter runApp GestureBinding使用介绍的详细内容,更多关于Flutter runApp GestureBinding的资料请关注我们其它相关文章!

(0)

相关推荐

  • Flutter RendererBinding作用源码分析

    目录 分析 PipelineOwner flushLayout flushCompositingBits flushPaint flushSemantics initRenderView scheduleInitialLayout scheduleInitialPaint 分析 RendererBinding 的作用是负责render tree 和flutter engine之间的连接. 我们在启动App的时候,首先会创建 PiplineOwner ,然后通过platformDispatcher

  • Flutter图片缓存管理ImageCache原理分析

    目录 引言 PaintingBinding 减少图片缓存 增大阀值 思考 引言 设计: 嗯? 这个图片点击跳转进详情再返回图片怎么变白闪一下呢?产品: 是啊是啊! 一定是个bug开发: 囧囧囧 在开发过程中, 也许你也遇到过这样一个场景. 进入一个页面后,前一个页面的图片都会闪白一下. 或者在列表中,加载很多列表项后,之前列表中的图片都需要重新加载.你有没有想过这一切的原因是什么呢? 没错! 它就是我们今天介绍的主人公 --- ImageCache 可能有些人对ImageCache还有些陌生,

  • Flutter runApp到渲染上屏分析详解

    目录 起源 分析准备 ensureInitialized scheduleAttachRootWidget scheduleWarmUpFrame 总结 起源 flutter作为一个跨平台的框架,在绘制上体现出了它跨平台的良好性能.那么,它是如何从runApp()后 绘制上屏的呢?本文将与你一起去探索这一过程. ps: 为了思维不中断, 本文仅对整体流程作分析,不会深入分析具体实现 我们运行一个flutter app ,入口一定是从runApp() 中进行的. 那么flutter 在runApp

  • Flutter SystemChrome使用方法详解

    目录 引言 setPreferredOrientations 设置横屏或坚屏 setEnabledSystemUIMode 设置全屏显示 setSystemUIOverlayStyle 设置 overlay 样式, 全屏播放视频 setSystemUIChangeCallback AnnotatedRegion 引言 SystemChrome 控制操作系统图形界面的特定方面以及它如何与应用程序交互. 需要注意的是在使用的时候一定要保证先执行 WidgetsFlutterBinding.ensur

  • Flutter最小刷新范围探索ValueListenableBuilder使用详解

    目录 引子 ValueListenableBuilder 如何用 怎么做 不足点 引子 管理对象太多? 刷新管理太麻烦 ? Flutter刷新范围控制不好 ? 不妨看看本文 , 希望提供给你一些思路吧 ! 说起 Flutter 刷新, 你的第一印象是什么 ? setState ? 是的, 只要使用过 Flutter 的人, 第一印象都必然是 setState , 但是由于 setState 滥用的问题, 性能问题就脱颖而出. 因此产出了诸如 Fish_redux 之流, 这些框架尽可能的使用 S

  • Flutter TV Android端开发技巧详细教程

    目录 前言 开发思路 先上效果 开发细节 使用RawKeyboardListener Provider层对事件进行处理 注意 总结 文件参考 TV keyCode详解 前言 最近公司有了新的业务,把现有Flutter Android项目应用到TV上去,这不,Asscre的活就来了. 本文详细说明Flutter for TV的两种实现方式,能力有限,不足之处欢迎指点,哈哈哈 开发思路 在开发之前,我们先设定一下我们的思路. 即,如何对原有程序代码侵入式最小.性能最佳.可玩性更高做出设定. 那么,通

  • Flutter CustomPaint绘制widget使用示例

    目录 CustomPaint 介绍 使用 CustomPaint size 的大小. isComplex willChange foregroundPainter 动画 CustomPaint 介绍 Flutter CustomPaint 提供了一个 canvas,可以在绘制阶段在上面进行绘制内容. 需要绘制时,CustomPaint 首先要求它的 painter 在当前画布上绘画,然后它绘画它的 child,在绘画完它的 child 之后,要求他的 foregroundPainter 绘画.

  • Flutter开发技巧ListView去除水波纹方法示例

    正文 ScrollConfiguration( behavior: NoScrollBehaviorWidget(), child: ListView( ...... ...... ), ), 调用ScrollConfiguration官方类,实现behavior NoScrollBehaviorWidget用于去除水波纹的自定义Widget import 'package:flutter/material.dart'; /// 去除listview水印 /// ScrollConfigurat

  • Android 集成Flutter

    目录 Android 集成Flutter 1, Hello Flutter 2, 引入 Flutter 模块 3,使用Flutter 3.1 添加依赖 3.2 运行Flutter页面 3.2.1 添加Flutter页面 4,Flutter APK 解析 5,踩过的坑 Android 集成Flutter Flutter 作为 Google 开源的新一代跨平台.高性能 UI 框架,旨在帮助开发者高效地构建出跨平台的.UI 与交互体验一致的精美应用,推出后一直倍受开发者的青睐. 当需要开发一个全新的应

  • Android集成Flutter

    目录 Android 集成Flutter 1, Hello Flutter 2, 引入 Flutter 模块 3,使用Flutter 3.1 添加依赖 3.2 运行Flutter页面 4,Flutter APK 解析 5,踩过的坑 Android 集成Flutter Flutter 作为 Google 开源的新一代跨平台.高性能 UI 框架,旨在帮助开发者高效地构建出跨平台的.UI 与交互体验一致的精美应用,推出后一直倍受开发者的青睐. 当需要开发一个全新的应用时,我们可以很方便地从零开始,完全

  • Android开发Flutter 桌面应用窗口化实战示例

    目录 前言 一.应用窗口的常规配置 应用窗口化 自定义窗口导航栏 美化应用窗口 二.windows平台特定交互 注册表操作 执行控制台指令 实现应用单例 三.桌面应用的交互习惯 按钮点击态 获取应用启动参数 四.写在最后 前言 通过此篇文章,你可以编写出一个完整桌面应用的窗口框架. 你将了解到: Flutter在开发windows和Android桌面应用初始阶段,应用窗口的常规配置: windows平台特定交互的实现,如:执行控制台指令,windows注册表,应用单例等: 桌面应用的交互习惯,如

  • Flutter集成到已有iOS工程的方法步骤

    前言 之前写过一篇介绍flutter集成到Android工程的文章,这次总结记录一下自己把flutter集成到iOS的流程,以及遇到的问题以及和解决方法供大家参考. 创建flutter_module 要在iOS工程中集成flutter,首先我们需要创建一个flutter_module,创建的方法有两种: 使用Android studio创建 使用Android studio创建在上一篇新版Flutter集成到已有Android项目中有介绍,这里不再赘述. 使用flutter命令创建 在指定目录下

  • Flutter桌面开发windows插件开发

    目录 前言 插件介绍 windows插件编写 Windows插件的一些坑 前言 通过此篇文章,你将了解到: Flutter插件的基本介绍: windows插件开发的真实踩坑经验. 我们都知道,Flutter的定位更多是作为一个跨平台的UI框架,对于原生平台的功能,开发过程中经常需要插件来提供.不幸的是Windows的生态又极其不完整,插件开发必不可少.但网上windows的文章少之又少,所以本篇文章,我们一起来聊聊插件开发的一些技巧. 插件介绍 Flutter的插件主要分两种:package和p

  • Flutter输入框TextField属性及监听事件介绍

    textField用于文本输入,它提供了很多属性: const TextField({ ... TextEditingController controller, FocusNode focusNode, InputDecoration decoration = const InputDecoration(), TextInputType keyboardType, TextInputAction textInputAction, TextStyle style, TextAlign textA

  • Flutter有无状态类与State及生命周期详细介绍

    目录 无状态类 有状态类 状态 State生命周期 Flutter中的生命周期类似于Vue.React中的生命周期一样,有初始化.状态更新.停用.销毁等. 在React中,组件分为函数式组件和类式组件,它们的区别就是一个无状态.一个有状态.那么在Flutter中亦是如此,它有两种类,一种是无状态类,一种是有状态类.其生命周期的使用就是有状态类的特定用法. 无状态类 无状态类内部有build方法,在表面上看 每次数据更新都会执行build方法.但实际上,在组件树中,当每次数据发生变更时,无状态类都

  • Flutter上的数据监控深入理解

    前言 最近看公司Flutter项目的时候,发现想要分析数据非常的困难,不是数据缺失就是数据异常,作为一个成熟的企业来说这是非常危险的,缺少了数据就像船只在海上航行的时候没有了方向,将会变得无所适从,所以这周花了点时间去优化. 我们要关注什么数据 对于Flutter这样的组件来说,我们需要关注的数据无非是两项: 性能数据 异常数据 这两项数据是我们监控整个Flutter应用是否优秀的最基础也是最重要的指标.性能数据能够帮我们分析出Flutter对比Native,RN,Weex等框架是否有优势,而异

随机推荐