Flutter-触控事件处理-Pointer Event

138 阅读2分钟

在移动端,各个平台或UI系统的原始指针事件模型基本都是一致的,即:一次完成的事件分为三个阶段:手指按下、手指移动、手指抬起。更高级别的手势(如双击、拖动、捏合等)都是基于这些原始事件进行识别的。

当手指按下时,Flutter会对应程序执行命中测试(hitTest),以确定指针和屏幕接触的位置存在哪些组件(Widget),iOS中类似函数pointInside判断点击区域命中。指针按下事件(以及该指针后续事件)然后被分发到由命中测试发现的最内部的组件,然后从那里开始,事件会在组件树中向上冒泡(iOS中hitTest),这些事件会从内部的组件被分发到组件树根的路径上的所有组件,Flutter中没有机制可以取消或停止冒泡过程,iOS是可以的。需要注意的是,只有通过命中测试的组件才能触发事件。

Listener

Flutter中可以使用Listener来监听原始触摸事件:

Listener({
  Key key,
  this.onPointerDown, //手指按下回调
  this.onPointerMove, //手指移动回调
  this.onPointerUp,//手指抬起回调
  this.onPointerCancel,//触摸事件取消回调
  this.behavior = HitTestBehavior.deferToChild, //先忽略此参数,后面小节会专门介绍
  Widget child
})

使用实例:

class _PointerMoveIndicatorState extends State<PointerMoveIndicator> {
  PointerEvent? _event;

  @override
  Widget build(BuildContext context) {
    return Listener(
      child: Container(
        alignment: Alignment.center,
        color: Colors.blue,
        width: 300.0,
        height: 150.0,
        child: Text(
          '${_event?.localPosition ?? ''}',
          style: TextStyle(color: Colors.white),
        ),
      ),
      onPointerDown: (PointerDownEvent event) => setState(() => _event = event),
      onPointerMove: (PointerMoveEvent event) => setState(() => _event = event),
      onPointerUp: (PointerUpEvent event) => setState(() => _event = event),
    );
  }
}

PointerDownEvent、PointerMoveEvent、PointUpEvent都是PointerEvent的子类,其包含属性:

  • position:指针相对于全局坐标的偏移
  • localPosition:指针相对于本身布局的坐标偏移
  • delta:两次指针移动事件的距离(PointerMoveEvent)
  • pressure:按压力度,如果手机屏幕支持压力传感器,此属性才有意义。
  • orientation:指针移动方向,是一个角度值。

忽略指针事件

如果不想让某个子树响应PointerEvent的话,可以使用IgnorePointer和AbsorbPointer,这两个组件都能阻止子树接收指针事件,不同在于AbsorbPointer本身会参与命中,而IgnorePointer不会参与,也就是AbsorbPointer本身可以接收指针事件,其子组件不行。而IgnorePointer则都不可以。

实例:

Listener(
  child: AbsorbPointer(
    child: Listener(
      child: Container(
        color: Colors.red,
        width: 200.0,
        height: 100.0,
      ),
      onPointerDown: (event)=>print("in"),
    ),
  ),
  onPointerDown: (event)=>print("up"),
)