背景 移动设备
上的各种点击事件与 web
上完全不一样,在 web
上,应用与用户交互是通过 鼠标
,只能利用鼠标的 单击
操作;而在 移动设备
上,是通过 手势系统
,用户是通过 触摸屏幕
与应用交互的,这里的情况比 web
上要复杂很多,比如 App 需要判断用户的触摸到底是在滚动页面,还是滑动一个 widget,或者只是一个单纯的点击。甚至还有多点同时触控的情况。
React Native
是通过 Gesture Responder System 来管理 app 中的 手势操作
的整个生命周期的。
如何响应用户的触摸事件
利用 gesture responder system
,一个View
只需要要实现了一些定义好的方法,就可以响应触摸事件了:
- View.props.onStartShouldSetResponder: (evt) => true, – 在用户开始触摸的时候(手指刚刚接触屏幕的瞬间),是否愿意成为响应者?
- View.props.onMoveShouldSetResponder: (evt) => true, – 如果 View 不是响应者,那么在每一个触摸点开始移动(没有停下也没有离开屏幕)时再询问一次:是否愿意响应触摸交互呢?
如果 View 返回 true,并开始尝试成为响应者,那么会触发下列事件之一:
- View.props.onResponderGrant: (evt) => {} – View 现在要开始响应触摸事件了。这也是需要做高亮的时候,使用户知道他到底点到了哪里。
- View.props.onResponderReject: (evt) => {} – 响应者现在“另有其人”而且暂时不会“放权”,请另作安排。
如果 View 已经开始响应触摸事件了,那么下列这些处理函数会被一一调用:
- 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 种不同的响应方法
- 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
中的回调函数的加强版本:
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) => {...}