PanResponder
PanResponder
类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。
默认情况下PanResponder
会通过InteractionManager
来阻止长时间运行的 JS 事件打断当前的手势活动。
它提供了一个对触摸响应系统响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的gestureState
对象:
onPanResponderMove: (event, gestureState) => {}
原生事件是指由以下字段组成的合成触摸事件:
nativeEvent
changedTouches
- 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)identifier
- 触摸点的 IDlocationX
- 触摸点相对于父元素的横坐标locationY
- 触摸点相对于父元素的纵坐标pageX
- 触摸点相对于根元素的横坐标pageY
- 触摸点相对于根元素的纵坐标target
- 触摸点所在的元素 IDtimestamp
- 触摸事件的时间戳,可用于移动速度的计算touches
- 当前屏幕上的所有触摸点的集合
一个gestureState
对象有如下的字段:
stateID
- 触摸状态的 ID。在屏幕上有至少一个触摸点的情况下,这个 ID 会一直有效。moveX
- 最近一次移动时的屏幕横坐标moveY
- 最近一次移动时的屏幕纵坐标x0
- 当响应器产生时的屏幕坐标y0
- 当响应器产生时的屏幕坐标dx
- 从触摸操作开始时的累计横向路程dy
- 从触摸操作开始时的累计纵向路程vx
- 当前的横向移动速度vy
- 当前的纵向移动速度numberActiveTouches
- 当前在屏幕上的有效触摸点的数量
基本用法
componentWillMount: function() {
this._panResponder = PanResponder.create({
// 要求成为响应者:
onStartShouldSetPanResponder: (evt, gestureState) => true,
onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
// 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!
// gestureState.{x,y} 现在会被设置为0
},
onPanResponderMove: (evt, gestureState) => {
// 最近一次的移动距离为gestureState.move{X,Y}
// 从成为响应者开始时的累计手势移动距离为gestureState.d{x,y}
},
onPanResponderTerminationRequest: (evt, gestureState) => true,
onPanResponderRelease: (evt, gestureState) => {
// 用户放开了所有的触摸点,且此时视图已经成为了响应者。
// 一般来说这意味着一个手势操作已经成功完成。
},
onPanResponderTerminate: (evt, gestureState) => {
// 另一个组件已经成为了新的响应者,所以当前手势将被取消。
},
onShouldBlockNativeResponder: (evt, gestureState) => {
// 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
// 默认返回true。目前暂时只支持android。
return true;
},
});
},
render: function() {
return (
<View {...this._panResponder.panHandlers} />
);
},
示例
PanResponder
works with Animated
API to help build complex gestures in the UI. The following example contains an animated View
component which can be dragged freely across the screen
- 函数式组件
- Class 组件
还可以看看官方示例 RNTester 中的 PanResponder.
文档
方法
create()
static create(config)
@param {object} 配置所有响应器回调的加强版本,不仅仅包括原本的ResponderSyntheticEvent
,还包括PanResponder
手势状态的回调。你只要简单的把onResponder*
回调中的Responder
替换为PanResponder
。举例来说,这个config<
对象可能看起来像这样:
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) => {...}
通常来说,对那些有对应捕获事件的事件来说,我们在捕获阶段更新 gestureState 一次,然后在冒泡阶段直接使用即可。
注意 onStartShould* 回调。他们只会在此节点冒泡/捕获的开始/结束事件中提供已经更新过的gestureState
。一旦这个节点成为了事件的响应者,则所有的开始/结束事件都会被手势正确处理,并且gestureState
也会被正确更新。(numberActiveTouches)有可能没有包含所有的触摸点,除非你就是触摸事件的响应者。