Gesture手势检测和滑动冲突

最近flutter稳定版本由1.5升级到了1.7,GestureDetector手势检测类也得到了完善,新增了很多事件回调方法。接下来主要介绍下GestureDetector基本使用、注意事项、1.5到1.7升级引起的问题和滑动冲突。

GestureDetector简介

  • GestureDetector接受child参数,检测child上手势操作的回调

  • downcancel

    GestureRecognizer之间相互竞争,down事件可能会有多个手势生出并接收回调,当某一个事件流程正式胜出,其他GestureRecognizer会调用其cancel方法

    // down
    onTapDown;
    onVerticalDragDown;
    onHorizontalDragDown;
    onPanDown;
    // cancel
    onTapCancel;
    onVerticalDragCancel;
    onHorizontalDragCancel;
    onPanCancel;
    
  • tap单击

    事件回调顺序onTapDown -> onTapUp -> onTap

    • onTap: 单击回调
    • onTapUp: 单击手势抬起回调
  • longPress长按

    事件回调顺序onLongPressStart -> onLongPress -> onLongPressMoveUpdate -> onLongPressEnd -> onLongPressUp

    • onLongPressStart:长按开始
    • onLongPress:长按回调
    • onLongPressMoveUpdate:长按移动
    • onLongPressEnd:长按事件结束
    • onLongPressUp:长按手势抬起
  • onDoubleTap双击回调

  • drag水平/垂直拖拽

    事件回调顺序onXXDragStart -> onXXDragUpdate -> onXXDragEnd

    • onXXDragStart:拖拽开始
    • onXXDragUpdate:拖拽过程移动
    • onXXDragEnd:拖拽结束
  • scale缩放

    事件回调顺序onScaleStart -> onScaleUpdate -> onScaleEnd

    • onScaleStart:缩放开始

    • onScaleUpdate:缩放更新

    • onScaleEnd:缩放结束

  • pan拖拽

    事件回调顺序onPanStart -> onPanUpdate -> onPanEnd

    • onPanStart:拖拽开始
    • onPanUpdate:拖拽过程移动
    • onPanEnd:拖拽结束

Listener简介

如果需要处理原始用户手势事件,可以使用Listner,其提供了原始手指操作的回调,核心方法有onPointerDownonPointerMoveonPointerUp,每一个事件流都是按照onPointerDown -> onPointerMove -> onPointerUp的顺序进行的,可以继承至Listner定制自定义手势检测。

  • onPointerDown:手指按下屏幕
  • onPointerMove:手指滑动
  • onPointerUp:手指离开屏幕

GestureDetector手势事件冲突

  • scalepan事件冲突,不能同时存在,建议直接使用scaleScaleUpdateDetails参数中,如果scale == 1则可以认为进入pan流程,前后两个focalPoint的差值即是DragUpdateDetails中的delta
  • HorizontalDragVerticalDrag不能共存,且如果存在scale的话,Drag事件优先级比较高,scale事件将被忽略。如果既要检测横向拖拽又要检测纵向拖拽,有两种方案:
    • GestureDetector嵌套,分别提供vertivalDraghorizontalDrag的回调,优势是简单方便,劣势是不能检测任意方向上的滑动
    • pan事件处理,直接处理pan事件流,可以检测到任意方向上的拖拽,有点是比较灵活和全面,缺点是稍显复杂

升级1.7遇到的问题和解决方案

1.5及1.5以前的版本可以嵌套GestureDetector同时检测scalepan,嵌套内层的GestureDetector优先处理事件流,如果内层嵌套不处理,则外层嵌套处理事件流,非常方便。

1.7上scale事件完全成为pan事件流的超集,不能共存,且不能嵌套,需要在scale相关回调中自行判断是滑动、缩放还是转动事件,通常,在不考虑转动事件下,认为若scale == 1为拖拽事件流,否则为缩放事件流,再进行相应操作。

滑动冲突的解决方案

典型场景,TabBarView结合内部可以滑动的view,例如大图页面ScalableImageWidget,会产生典型的滑动冲突。

解决方案是内部ScalableImageWidget优先级较高,决定是否处理滑动事件,若不处理,则移交给外部TabBarView处理。具体如下:

  1. root页面持有TabBarView和其child ScalableImageWidget构造方法,设置标志位_needHandleScroll决定TabBarViewphysics属性取PageScrollPhysics还是NeverScrollableScrollPhysics,设置ScalableImageWidget回调scrollStateCallback
  2. ScalableImageWidget根据边界条件决定是否消费滑动事件,若不消费,则调用ScrollStateCallback回调设置root页面_needHandleScroll标志位,将处理权交给TabBarView
  3. TabBarView获取了滑动事件处理权,则监听滑动动画的执行,滑动动画结束后将处理权移交给内部child

你可能感兴趣的:(Gesture手势检测和滑动冲突)