Flutter 学习之旅(三十一) 触摸事件学习(一)

在移动端,各个系统对触摸事件处理应该是差不多的,一个触摸事件大致分为 按下 移动 抬起, 其他的比如单机 双击 拖动都是由这些事件组合起来的,
在Flutter 中最原始的触摸事件是由Listener来监听的,先来看一下构造方法

Listener({
    Key key,
///手指按下回调   方法
    this.onPointerDown,
///手指移动回调   方法
    this.onPointerMove,
    // We have to ignore the lint rule here in order to use deprecated
    // parameters and keep backward compatibility.
    // TODO(tongmu): After it goes stable, remove these 3 parameters from Listener
    // and Listener should no longer need an intermediate class _PointerListener.
    // https://github.com/flutter/flutter/issues/36085
    @Deprecated(
      'Use MouseRegion.onEnter instead. See MouseRegion.opaque for behavioral difference. '
      'This feature was deprecated after v1.10.14.'
    )
    this.onPointerEnter,
    @Deprecated(
      'Use MouseRegion.onExit instead. See MouseRegion.opaque for behavioral difference. '
      'This feature was deprecated after v1.10.14.'
    )
    this.onPointerExit,
    @Deprecated(
      'Use MouseRegion.onHover instead. See MouseRegion.opaque for behavioral difference. '
      'This feature was deprecated after v1.10.14.'
    )
    this.onPointerHover,
    this.onPointerUp,
    this.onPointerCancel,
    this.onPointerSignal,
    this.behavior = HitTestBehavior.deferToChild,
    Widget child,
  }) 

HitTestBehavior 在碰撞测试过成功中起着决定性的作用,

opaque 在碰撞测试过程中,只要接收到触摸事件,测视为碰撞成功,

下面这个是碰撞测试的代码,主要看hitTestSelf 这个方法,只要behavior==HitTestBehavior.opaque则认为碰撞成功

  @override
  bool hitTest(BoxHitTestResult result, { Offset position }) {
    bool hitTarget = false;
    if (size.contains(position)) {
      hitTarget = hitTestChildren(result, position: position) || hitTestSelf(position);
      if (hitTarget || behavior == HitTestBehavior.translucent)
        result.add(BoxHitTestEntry(this, position));
    }
    return hitTarget;
  }

  @override
  bool hitTestSelf(Offset position) => behavior == HitTestBehavior.opaque;

deferToChild

只在当前widget的区域作为触摸事件碰撞测试的区域,同样是上面的方法 这次看hitTestChildren 这个方法

  @override
  bool hitTestChildren(BoxHitTestResult result, { Offset position }) {
    return child?.hitTest(result, position: position) ?? false;
  }

这里的意思就是Listener 是否有child ,没有就返回false 有就返回子widget的碰撞测试结果
下面继续看hitTest 这个方法

  bool hitTest(BoxHitTestResult result, { @required Offset position }) {
    if (_size.contains(position)) {
      if (hitTestChildren(result, position: position) || hitTestSelf(position)) {
        result.add(BoxHitTestEntry(this, position));
        return true;
      }
    }
    return false;
  }

先判断自身是否处于响应区域之内,如果不在,直接就返回false,如果在就尝试碰撞子控件和自己
递归调用,从控件树自下而上的得到了一个相应控件列表,最后会使用result中最上层一个widget响应本次触摸事件
例子

Listener(
            onPointerDown: (event) {
              printString('onPointerDown');
              setState(() {
                _event = event;
              });
            },
            onPointerMove: (event) {
              printString('onPointerMove :+${event.position}');
              setState(() {
                _event = event;
              });
            },
            onPointerUp: (event) {
              printString('onPointerUp');
              setState(() {
                _event = event;
              });
            },
            child: Container(
              width: double.infinity,
              height: 150,
              color: Colors.redAccent,
              alignment: Alignment.center,
              child: Text(_event?.toString() ?? ""),
            ),
          )

PointerDownEvent PointerMoveEvent PointerUpEvent 都是PointerEvent的子类,PointerEvent有两个比较重要的属性,

position:

它是鼠标相对于当对于全局坐标的偏移。

delta:

两次指针移动事件(PointerMoveEvent)的距离。

如何让widget忽略PointerEvent

IgnorePointer和AbsorbPointer

IgnorePointer

直接拦截触摸事件,在他的范围内父控件的触摸事件也不响应,

AbsorbPointer

将自身刨除在触摸时间外,他和他的子widget不响应触摸事件,但是父widget 仍然会响应

Listener(
  child: AbsorbPointer(
    child: Listener(
      child: Container(
        color: Colors.red,
        width: 100,
        height: 100,
      ),
      onPointerDown: (event)=>print("two"),
    ),
  ),
  onPointerDown: (event)=>print("one"),
)

这里使用的是AbsorbPointer,拦截他和他子widget 的触摸事件,所以只打印one ,如果换做IgnorePointer 则两个都不会打印

我学习flutter的整个过程都记录在里面了
https://www.jianshu.com/c/36554cb4c804

最后附上demo 地址

https://github.com/tsm19911014/tsm_flutter

你可能感兴趣的:(Flutter 学习之旅(三十一) 触摸事件学习(一))