react-native-gesture-handler 使用

安装

yarn add react-native-gesture-handler

link到原生项目中

react-native link react-native-gesture-handler 

为什么写这个文档

官方文档看的难受。React Native Gesture Handler 官网文档

为什么要使用这个库

更加的流畅、可靠。

react-native自带的PanResponder手势监视器由JS响应器系统控制而react-native-gesture-handler是在UI线程中识别和跟踪手势。

若使用RN官方提供的手势管理在与发生在主线程上的触摸交互(如iOS滑块或任何滚动视图)时,经常会遇到问题。由于主线程必须同步决定JS或滚动视图是否应该成为响应器,而JS只能异步响应并不能立即拒绝Native事件的响应,导致手势操作被这些Native组件劫持。

ps: 上面提到的JS不能立即拒绝Native事件的响应对应PanResponder中的onPanResponderTerminationRequest方法,当该方法返回false时表示拒绝其他组件响应当前的手势。

问题场景示例:

  1. 使用react-native-scroll-tab-view组件作为导航,左右切换视图。
  2. 在react-native-scroll-tab-view内嵌套了Slider组件或者其他使用PanResponder手势监视器实现了某些手势操作。
  3. 使用时常常会出现在这些子组件做滑动操作时,触发了react-native-scroll-tab-view组件的滑动的问题。

详情react-native项目中的这个issue:How to stopPropagation touch event

我解决这个问题过程: 如何在RN的可滚动组件内设置一个禁止滚动的区域

组件与方法说明

组件通用属性、方法Common handler properties

enabled:是否响应手势操作。
shouldCancelWhenOutside:当前手势离开当前组件区域时是否进入CANCELLED或FAILD状态。
simultaneousHandlers
waitFor:等待其他事件结束时才响应手势操作
hitSlop:可以控制视图区域的哪个部分来开始识别手势。与View组件的hitSlop类似
onGestureEvent:手势ACTIVE状态时执行的回调
onHandlerStateChange:手势状态改变时的回调

事件参数

onHadlerStateChange与onGestureEvent回调的参数event(主要用到的就是nativeEvent属性)


//event的属性声明
interface event {
    nativeEvent: nativeEvent
    //...
}

//nativeEvent的属性声明
interface nativeEvent {
    absoluteX: number //相对于根视图,指针的当前位置的X坐标(当放置多个手指时的手指或前导指针)。
    absoluteY: number //相对于根视图,指针的当前位置的Y坐标(当放置多个手指时的手指或前导指针)。
    handlerTag: number
    numberOfPointers: number //表示当前放置在屏幕上的指针(手指)的数量。
    state: number //手势处理程序的当前状态
    translationX: number //手势开始到目前为止在水平方向上的移动距离。它与PanResponder中的dx类似
    translationY: number //手势开始到目前为止在垂直方向上的移动距离。
    velocityX: number //水平移速
    velocityY: number //垂直移速
    x: number //当前手势位置相对于附加PanGestureHandler的视图的X
    y: number //当前手势位置相对于附加PanGestureHandler的视图的Y
}

手势操作过程中,react-native-gesture-handler提供Handlers组件的State会不断变化,开发者根据State来响应不同状态下的操作。详情查看Handler State

与PanResponder对照

说明PanGestureHandlerPanResponder
是否声明成为触摸手势响应者或是否声明成为移动手势的响应者-onStartShouldSetPanResponder ,onMoveShouldSetPanResponder
触摸手势开始onHadlerStateChange, State.BEGANonPanResponderGrant
手势移动过程中执行的回调onHadlerStateChange, onGestureEvent, State.ACTIVEonPanResponderMove
手势释放onHadlerStateChange, State.END或State.FAILEDonPanResponderRelease
是否将响应手势的操作交给其他组件-onPanResponderTerminationRequest
手势操作被其他组件或事件打断后的回调-onPanResponderTerminate

使用对比:

PanGestureHandler

import {PanGestureHandler, State} from 'react-native-gesture-handler'

//...

<PanGestureHandler
    onHadlerStateChange = ({nativeEvent}) => {
        switch (nativeEvent.state) {
          case State.UNDETERMINED:
            console.log('等待手势')
            break;
          case State.BEGAN:
            console.log('手势开始')
            break;
          case State.CANCELLED:
            console.log('手势取消')
            break;
          case State.ACTIVE:
            console.log('手势活跃')
            break;
          case State.END:
            console.log('手势结束')
            break;
          case State.FAILED:
            console.log('失败')
            break;
          default:
            console.log('其他')
            break;
        }
    }
    onGestureEvent = ({ nativeEvent }) => {
    
    }
>
    <Animated.View 
        //...
    >
    </Animated.View>
</PanGestureHandler>

PanResponder

import {PanResponder} from 'react-native'

<Animated.View
    {
        ...PanResponder.create({
            onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
            onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
            onPanResponderGrant: this._handlePanResponderGrant,
            onPanResponderMove: this._handlePanResponderMove,
            onPanResponderRelease: this._handlePanResponderEnd,
            onPanResponderTerminationRequest: this._handlePanResponderRequestEnd,
            onPanResponderTerminate: this._handlePanResponderEnd,
        }).panHandlers
    }
>
</Animated.View>