• Flutter中的事件处理


    Flutter中的事件处理

    无论是在Android中还是iOS中,都是有事件响应的。其主要是通过手指进行触摸,当手指接触到屏幕后,便开始进行事件响应了。

    基本概念:指针事件

    在Flutter的原始事件模型中,在手指接触屏幕发起接触事件时,flutter会首先确定手指与屏幕发生接触的位置上究竟有哪些组件。然后通过命中测试(Hit Test)交给最内层的组件去响应。换句话说,也就是先从渲染树的最底层的根的位置向上遍历,直到遍历到根结点位置。

    flutter中的主要的事件响应分为三个部分组成 PointerDownEventPointerMoveEventPointerUpEvent 三个事件,分别是手指下落事件,手指移动事件,手指抬起事件。PointerEvent 是Flutter的原始指针事件的基础类。主要返回有

    • position:全局坐标的偏移量
    • delta:两次指针移动事件的距离
    • pressure:按压力度,如果手机不支持,始终返回1
    • orientation:指针移动方向,是一个角度值

    对于原始指针事件的监听,Flutter提供了一个Listener类。这个类可以用它监听包裹的子组件的原始指针事件。

    Listener(
    	onPointerDown:(downPointEvent){},
    	onPointerMove:(movePointEvent){},
    	onPointerUp:(upPointEvent){},
      behavior:HitTestBehavior,
    	child: Widget
    )
    

    behavior是决定子组件如何响应命中测试,值类型是HitTestBehavior,是一个枚举类型。主要的取值有

    • deferToChild:子组件一个接一个地命中测试,如果子组件中有命中测试的,那么当前组件会收到指针事件,并且父组件也会收到指针事件。
    • opaque:在进行命中测试时,当前组件会被当成不透明进行处理,单击的响应区域即为单击区域。
    • translucent:组件自身和底部可视区域都能够响应命中测试,当点击顶部组件时,顶部组件和底部组件都可以接收到指针事件。

    忽略事件

    两个组件 AbsorbPointer , IgnorePointer

    编号 组件名称 组件说明
    1 AbsorbPointer 其包裹的组件不能够响应事件,但是其本身能够响应指针事件
    2 IgnorePointer 包裹的组件以及其本身都不能够响应指针事件

    手势识别:GestureDetector

    如果想从组件层监听手势,可以使用GestureDetector等手势响应组件。该组件可以监听各种触摸的行为,常用的事件如下:

    编号 事件名称 描述
    1 onTapDown 接触屏幕时触发
    2 onTapUp 离开屏幕时触发
    3 onTap 点击屏幕时触发
    4 onTapCancel 触发onTapDown事件但不会触发onTap事件
    5 onDoubleTap 用户连续两次在同一位置快读点击屏幕
    6 onLongPress 在相同位置与屏幕保持长时间接触
    7 onVerticalDragStart 与屏幕接触并可能开始垂直移动
    8 onVerticalDragUpdate 与屏幕接触并沿垂直方向移动
    9 onVerticalDragEnd 之前与屏幕接触并垂直移动的指针不再与屏幕接触
    10 onHorizontalDragStart 与屏幕接触并可能开始水平移动
    11 onHorizontalDragUpdate 与屏幕接触并已沿水平方向移动
    12 onHorizontalDragEnd 之前与屏幕接触并水平移动的指针不再与屏幕接触

    如果同时监测onTap和onDoubleTap,那么在onTap后有200ms的延迟。

    GestureDetector之所以能够识别各种手势,是因为其内部使用了一个或者多个GestureRecognizer手势识别器。在使用手势识别器后,需要调用 dispose() 进行资源的释放,否则会造成大量的资源消耗。

    手势竞争与冲突

    在flutter中,引入了手势竞技场的概念,用来识别究竟是哪个手势最终响应用户事件。该 手势竞技场 通过综合对比用户触摸屏幕的时长、位移、拖拽方向来确定最终的手势。换句话说,如果在屏幕上拖拽一个小球,那么该小球就会通过手势竞技场进行判断移动的方向。一般只有单一方向,垂直移动或者水平移动。

    事件总线

    事件总线是广播机制的一种实现方式(广播为跨页面事件通信提供了有效的解决方案)。订阅者模式中包含两种角色:发布者和订阅者。在Flutter中:

    • 发布者主要负责在状态改变时通知所有的订阅者
    • 观察者则负责订阅事件并对接收到的事件进行处理。

    使用事件总线可以实现组件之间状态的共享,但是对于复杂场景来说,可以使用专门的管理框架例如:redux、ScopeModel或者Provider

    事件通知

    如果在一个比较复杂的页面进行数据传递,那么使用到 事件通知 这个机制,在子节点跨层级传递消息机制。在Flutter的组件树中,每一个节点都可以发送通知,通知会沿着当前节点向上传递,父节点则使用NotificationListener监听子节点传递的消息,这种机制称为 通知冒泡

    通知冒泡用户触摸事件冒泡 不太一样,通知冒泡可以中止,用户触摸事件冒泡不可以中止。

    自定义通知

    如果需要实现自定义通知,需要实现一个类并且继承 Notification 。在Notification类中,有一个dispatch() 可以用这个类进行分发事件通知。

    冒泡通知的原理

    因为通知 Notification 是通过dispatch进行触发的,因此查看dispatch的源码,如下:

    void dispatch(BuildContext? target) {
        // The `target` may be null if the subtree the notification is supposed to be
        // dispatched in is in the process of being disposed.
        target?.visitAncestorElements(visitAncestor);
    }
    

    可以知道,其是调用了visitAncestorElements方法,从当前元素开始向上遍历父元素。当遍历到根元素或者遍历回调返回false时,遍历过程中止。该冒泡通知的原理是一套自底向上的消息传递机制。

    这是小睿的博客,如果需要转载,请标注出处啦~ヾ(≧▽≦*)o谢谢。
  • 相关阅读:
    百万英雄答题值不值得您继续参加
    一个程序员&自媒体人的2017年终总结
    送书福利又来了,总共10本程序员技术书
    CCF 201912-2 回收站选址(100分)Java
    CCF 201912-1 报数 (100分)Java
    CCF 201909-2 小明种苹果(续)(100分)Java
    CCF 201909-1 小明种苹果(100分)Java
    初识JWT
    Redis学习——事务、消息订阅和发布
    Redis学习——数据类型及操作
  • 原文地址:https://www.cnblogs.com/Yunrui-blogs/p/15507368.html
Copyright © 2020-2023  润新知