React Native 中的 Gesture Responder System 和 PanResponder 探究

背景
移动设备上的各类点击事件与web上彻底不同, 在web上,应用与用户交互是经过鼠标,只能利用鼠标的单击操做;而在移动设备上,是经过手势系统,用户是经过触摸屏幕与应用交互的,这里的状况比web上要复杂不少,好比 App 须要判断用户的触摸究竟是在滚动页面,仍是滑动一个 widget,或者只是一个单纯的点击。甚至还有多点同时触控的状况。react

React Native 是经过 Gesture Responder System 来管理app中的手势操做的整个生命周期的。git

如何响应用户的触摸事件
利用gesture responder system,一个View只须要要实现了一些定义好的方法,就能够响应触摸事件了:github

  • View.props.onStartShouldSetResponder: (evt) => true, - 在用户开始触摸的时候(手指刚刚接触屏幕的瞬间),是否愿意成为响应者?
  • View.props.onMoveShouldSetResponder: (evt) => true, - 若是 View 不是响应者,那么在每个触摸点开始移动(没有停下也没有离开屏幕)时再询问一次:是否愿意响应触摸交互呢?

若是 View 返回 true,并开始尝试成为响应者,那么会触发下列事件之一:web

  • View.props.onResponderGrant: (evt) => {} - View 如今要开始响应触摸事件了。这也是须要作高亮的时候,使用户知道他到底点到了哪里。
  • View.props.onResponderReject: (evt) => {} - 响应者如今“另有其人”并且暂时不会“放权”,请另做安排。

若是 View 已经开始响应触摸事件了,那么下列这些处理函数会被一一调用:react-native

  • View.props.onResponderMove: (evt) => {} - 用户正在屏幕上移动手指时(没有停下也没有离开屏幕)。
  • View.props.onResponderRelease: (evt) => {} - 触摸操做结束时触发,好比"touchUp"(手指抬起离开屏幕)。
  • View.props.onResponderTerminationRequest: (evt) => true - 有其余组件请求接替响应者,当前的 View 是否“放权”?返回 true 的话则释放响应者权力。
  • View.props.onResponderTerminate: (evt) => {} - 响应者权力已经交出。这多是因为其余 View 经过onResponderTerminationRequest请求的,也多是由操做系统强制夺权(好比 iOS 上的控制中心或是通知中心)。

手势响应系统用起来可能比较复杂。因此RN利用了手势响应系统封装了一个抽象的Touchable实现(TouchableOpacity、TouchableHighlight等),用来作可触控的组件,使得你能够简单地以声明的方式来配置触控处理。他们能够绑定4种不一样的响应方法app

  • onPress
  • onPressIn
  • onPressOut
  • onLonePress

而对于手指滑动(拖拽)、多点触控等操做,利用上面的Touchable方法没法实现,因而RN 又在手势响应系统的基础上封装了一个 PanResponder 来处理更复杂的手势操做。封装后的PanResponder 方法的抽象程度更高,使用起来也更加方便:函数

panResponder = PanResponder.create({
    onStartShouldSetPanResponder: (evt, gestureState) => true,
    onMoveShouldSetPanResponder: (evt, gestureState) => true,
    onPanResponderGrant: (evt, gestureState) => {
        console.log('evt', evt)    
        console.log('gestureState', gestureState)
    },
    onPanResponderMove: (evt, gestureState) => {
        console.log('evt', evt)    
        console.log('gestureState', gestureState)
    },
    onPanResponderRelease: (evt, gestureState) => {
        console.log('evt', evt)    
        console.log('gestureState', gestureState)
    },
})
render() {
    <View style={styles.container}
        {...this.panResponder.panHandlers}
    > 
    ...
    </View>
}

PanResponder在手势响应系统的原生事件以外提供了一个新的gestureState对象,提供了更多实用的字段(具体能够看文档);而且handler响应器回调函数是原来gesture responder system中的回调函数的增强版本:this

onMoveShouldSetPanResponder: (e, gestureState) => {...}
onMoveShouldSetPanResponderCapture: (e, gestureState) => {...}
onStartShouldSetPanResponder: (e, gestureState) => {...}
onStartShouldSetPanResponderCapture: (e, gestureState) => {...}
onPanResponderReject: (e, gestureState) => {...}
onPanResponderGrant: (e, gestureState) => {...}
onPanResponderStart: (e, gestureState) => {...}
onPanResponderEnd: (e, gestureState) => {...}
onPanResponderRelease: (e, gestureState) => {...}
onPanResponderMove: (e, gestureState) => {...}
onPanResponderTerminate: (e, gestureState) => {...}
onPanResponderTerminationRequest: (e, gestureState) => {...}
onShouldBlockNativeResponder: (e, gestureState) => {...}
相关文章
相关标签/搜索