我们知道,react-native
封装了一系列的组件例如<Touchable**>
来提供触摸事件的反馈,另外Button
、Text
等组件也提供了简单的点击方法来给组件快速添加触摸事件。但是这些组件都是针对某个特定的效果,因其是定制的,所以可自定义、调整的部分就会很少,至多是效果有个选项。那么,如果我们希望做复杂的效果,改怎么办呢?答案是panResopner
。
先看下panResponder
的说明:
它可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。
它提供了一个对触摸响应系统响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的gestureState对象。
触摸整体流程
简单来说,就是它会将触摸中发生的每次事件,每次状态的转换都通过api提供出来,供开发者做深入的开发和操作。这里的状态和过程包括:
要求成为响应者
onStartShouldSetPanResponder: (evt, gestureState) => true, onStartShouldSetPanResponderCapture: (evt, gestureState) => true, onMoveShouldSetPanResponder: (evt, gestureState) => true, onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
- 1
- 2
- 3
- 4
开始手势操作
onPanResponderGrant: (evt, gestureState) => {}
- 1
触摸点移动
onPanResponderMove: (evt, gestureState) => {}
- 1
用户放开了所有的触摸点,且此时视图已经成为了响应者
onPanResponderTerminationRequest: (evt, gestureState) => true, onPanResponderRelease: (evt, gestureState) => {}
- 1
- 2
另一个组件已经成为了新的响应者,所以当前手势将被取消
onPanResponderTerminate: (evt, gestureState) => {}
- 1
返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者(暂只支持android)
onShouldBlockNativeResponder: (evt, gestureState) => { return true; }
- 1
- 2
- 3
整体的流程图是:
触摸事件参数
从上面的函数就可以看到,触摸事件中,基本都包含这两个参数:
nativeEvent
- changedTouches - 在上一次事件之后,所有发生变化的触摸事件的数组集合(即上一次事件后,所有移动过的触摸点)
- identifier - 触摸点的ID
- locationX - 触摸点相对于父元素的横坐标
- locationY - 触摸点相对于父元素的纵坐标
- pageX - 触摸点相对于根元素的横坐标
- pageY - 触摸点相对于根元素的纵坐标
- target - 触摸点所在的元素ID
- timestamp - 触摸事件的时间戳,可用于移动速度的计算
- touches - 当前屏幕上的所有触摸点的集合
gestureState
- stateID - 触摸状态的ID。在屏幕上有至少一个触摸点的情况下,这个ID会一直有效。
- moveX - 最近一次移动时的屏幕横坐标
- moveY - 最近一次移动时的屏幕纵坐标
- x0 - 当响应器产生时的屏幕坐标
- y0 - 当响应器产生时的屏幕坐标
- dx - 从触摸操作开始时的累计横向路程
- dy - 从触摸操作开始时的累计纵向路程
- vx - 当前的横向移动速度
- vy - 当前的纵向移动速度
- numberActiveTouches - 当前在屏幕上的有效触摸点的数量
这里先给出定义,具体的每个参数的时候,会在讲触摸move的时候一起讲
给组件添加触摸事件
给一个组件添加触摸事件很简单,有两步:
- 创建一个panResponder
- 将panResponder的panHandles传给这个组件
看下代码:
import React, {PureComponent, Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PanResponder,
} from 'react-native';
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
redViewBgColor: 'red',
}
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
},
onPanResponderMove: (evt, gestureState) => {
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({redViewBgColor: 'red'})
}
_highlight(){
this.setState({redViewBgColor: 'blue'})
}
render() {
return (
<View style={styles.container}>
<View style={[styles.redView,{backgroundColor: this.state.redViewBgColor}]}
{...this._panResponder.panHandlers}
></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
redView: {
width: 100,
height: 100,
marginTop: 100,
marginLeft: 100,
},
});
AppRegistry.registerComponent('TouchStartAndRelease', () => TouchStartAndRelease);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
onPanResponderGrant
是当用户触摸到屏幕时,我们需要给用户一个反馈,让他知道,触摸已经起作用了。这里我们将view变蓝。
onPanResponderRelease
是当用户触摸结束时,我们也要给个反馈,让用户知道触摸已经停止。这里我们将view变回红色。
之前记得看过,之所以native比web的效果用起来好很多,就是因为native的每个步骤,都会给用户反馈,让用户知道,他的行为已经有回应了。这也是我们在做前端包括交互设计的时候,非常需要注意的事情,要知道,用户是很不耐烦的,你一定要给用户一个不太需要思考的交互,不要让他去想诸如:‘我碰到这个按钮了吗?’,‘这个是这样用的吗?’类似的问题。感兴趣的可以看下一本书《Don’t make me think》。
效果如下:
触摸移动
nativeEvnet
locationX loactionY
我们试着在移动的时候,让view随着手指的移动而移动。这里主要需要处理onPanResponderMove函数,先试试用nativeEvent
的locationX
和locationY
来处理,代码如下:
import React, {PureComponent, Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PanResponder,
} from 'react-native';
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
backgroundColor: 'red',
marginTop: 100,
marginLeft: 100,
}
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
},
onPanResponderMove: (evt, gestureState) => {
console.log(`locationX : ${evt.nativeEvent.locationX} locationY : ${evt.nativeEvent.locationY}`);
this.setState({
marginLeft: evt.nativeEvent.locationX,
marginTop: evt.nativeEvent.locationY,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({
backgroundColor: 'red',
});
}
_highlight(){
this.setState({
backgroundColor: 'blue',
});
}
render() {
return (
<View style={styles.container}>
<View style={[styles.redView,
{
backgroundColor: this.state.backgroundColor,
marginTop: this.state.marginTop,
marginLeft: this.state.marginLeft,
}
]}
{...this._panResponder.panHandlers}
></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
redView: {
width: 100,
height: 100,
},
});
AppRegistry.registerComponent('TouchStartAndRelease', () => TouchStartAndRelease);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
在实际操作中,发现locationX
和locationY
的移动是非常跳跃的,和api上面的介绍并不一样。查了github
的issues
,发现很多人提locationX
在android
上面不准确或者不变的bug,但这个问题没有人提,所以我就提了一个,地址是: When I use panResponder.nativeEvent.locationX and locationY, it changes queite strange
效果如下:
pageX pageY
ok、根据介绍,pageX和pageY是触摸点相对于根元素的横纵坐标,其效果如何呢? 我们将上述代码中的locationX和locationY替换为pageX和pageY.代码:
import React, {PureComponent, Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PanResponder,
} from 'react-native';
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
backgroundColor: 'red',
marginTop: 100,
marginLeft: 100,
}
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
},
onPanResponderMove: (evt, gestureState) => {
console.log(`pageX : ${evt.nativeEvent.pageX} pageY : ${evt.nativeEvent.pageY}`);
this.setState({
marginLeft: evt.nativeEvent.pageX,
marginTop: pageY,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({
backgroundColor: 'red',
});
}
_highlight(){
this.setState({
backgroundColor: 'blue',
});
}
render() {
return (
<View style={styles.container}>
<View style={[styles.redView,
{
backgroundColor: this.state.backgroundColor,
marginTop: this.state.marginTop,
marginLeft: this.state.marginLeft,
}
]}
{...this._panResponder.panHandlers}
></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
redView: {
width: 100,
height: 100,
},
});
AppRegistry.registerComponent('TouchStartAndRelease', () => TouchStartAndRelease);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
reload下。看下效果:
这里发现,移动开始的时候,pageX和pageY其实会有个跳跃,但是在移动的过程中,其变化比较稳定。这里打了下log,发现本来是(100,100)的View,在点击的时候,(pageX,pageY)为(176,156),研究了下发现是因为我的触摸点相对于view其实是有距离的,所以造成了开始的跳跃。
接下里,我们在这个redView的外围增加一个view,看下获得的pageX和pageY是什么,代码:
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
backgroundColor: 'red',
marginTop: 100,
marginLeft: 100,
}
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
},
onPanResponderMove: (evt, gestureState) => {
console.log(`locationX : ${evt.nativeEvent.pageX} locationY : ${evt.nativeEvent.pageY}`);
this.setState({
marginLeft: evt.nativeEvent.pageX,
marginTop: evt.nativeEvent.pageY,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({
backgroundColor: 'red',
});
}
_highlight(){
this.setState({
backgroundColor: 'blue',
});
}
render() {
return (
<View style={styles.container}>
<View style={{height: 200,width: 200,backgroundColor:"grey"}}>
<View style={[styles.redView,
{
backgroundColor: this.state.backgroundColor,
marginTop: this.state.marginTop,
marginLeft: this.state.marginLeft,
}
]}
{...this._panResponder.panHandlers}
></View>
</View>
</View>
);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
效果:
这里可以看到,pageX和pageY确实是当前的屏幕坐标,和其父view没有关系
怎么解决跳跃的问题呢? 目前从nativeEvent中的参数来看,是没办法解决的,所以我们继续看下gesture中的参数。(后面会给出解决方案)
gesture
moveX moveY
这里先看下moveX moveY,定义是最近一次移动时的屏幕横坐标和纵坐标,从定义上讲,和nativeEvent中的pageX和pageY应该是一样的,我们看下demo。
代码:
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
backgroundColor: 'red',
marginTop: 100,
marginLeft: 100,
}
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
},
onPanResponderMove: (evt, gestureState) => {
console.log(`gestureState.moveX : ${gestureState.moveX} gestureState.moveY : ${gestureState.moveY}`);
this.setState({
marginLeft: gestureState.moveX,
marginTop: gestureState.moveY,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({
backgroundColor: 'red',
});
}
_highlight(){
this.setState({
backgroundColor: 'blue',
});
}
render() {
return (
<View style={styles.container}>
<View style={[styles.redView,
{
backgroundColor: this.state.backgroundColor,
marginTop: this.state.marginTop,
marginLeft: this.state.marginLeft,
}
]}
{...this._panResponder.panHandlers}
></View>
</View>
);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
效果和pageX,pageY一样,这里就不贴出来截屏了。
在有parentView的情况下,效果也是没有区别。
x0 y0
x0和y0定义写的很清楚:
x0 - 当响应器产生时的屏幕坐标
y0 - 当响应器产生时的屏幕坐标
就是当响应器产生时,即可以理解为触摸开始时,触摸的屏幕坐标。所以一旦触摸产生,x0 和 y0其实不会变了,除非这次触摸release,产生下次触摸。
dx dy
dx - 从触摸操作开始时的累计横向路程
dy - 从触摸操作开始时的累计纵向路程
这个定义写的也蛮清楚的,就是本次触摸的累积横向路程和纵向路程。嘿、还记得上面我们遇到的问题吗?pageX、pageY 和 moveX、moveY都会有的问题,第一次如果不是点击左上角来移动,第一会有点跳跃,因为我们不知道当前的触摸点相对于view的坐标,所以坐标会偏移一些。
有了dx和dy,我们就可以想办法解决这个问题了。我们只要记住上次这个view的left和top,然后set的时候,增加移动的距离,就解决了移动跳跃的问题了,先上代码:
import React, {PureComponent, Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PanResponder,
} from 'react-native';
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
backgroundColor: 'red',
marginTop: 100,
marginLeft: 100,
};
this.lastX = this.state.marginLeft;
this.lastY = this.state.marginTop;
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
},
onPanResponderMove: (evt, gestureState) => {
console.log(`gestureState.dx : ${gestureState.dx} gestureState.dy : ${gestureState.dy}`);
this.setState({
marginLeft: this.lastX + gestureState.dx,
marginTop: this.lastY + gestureState.dy,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
this.lastX = this.state.marginLeft;
this.lastY = this.state.marginTop;
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({
backgroundColor: 'red',
});
}
_highlight(){
this.setState({
backgroundColor: 'blue',
});
}
render() {
return (
<View style={styles.container}>
<View style={[styles.redView,
{
backgroundColor: this.state.backgroundColor,
marginTop: this.state.marginTop,
marginLeft: this.state.marginLeft,
}
]}
{...this._panResponder.panHandlers}
></View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
redView: {
width: 100,
height: 100,
},
});
AppRegistry.registerComponent('TouchStartAndRelease', () => TouchStartAndRelease);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
效果:
vx vy
接下来的参数是vx和vy,这里不详细介绍,给出定义:
vx - 当前的横向移动速度
vy - 当前的纵向移动速度
控制触摸是否响应
上面一直在讲move的时候的用法, 下面看下如何控制是否响应
onStartShouldSetPanResponder
这个很简单了,返回true,怎变成响应器,否则不会响应.但是当我真的去demo 的时候,诡异的事情发生了,onStartShouldSetPanResponder
return false,居然view还能移动。打断点看了下,原来是因为onMoveShouldSetPanResponder
是true,那么其移动是正常的。所以onStartShouldSetPanResponder
只控制当触摸开始时,不会执行onPanResponderGrant
函数。但是如果发生了move,则还是会走onPanResponderGrant函数。
上面简介的时候,还有个onStartShouldSetPanResponderCapture
没有介绍,这个我尝试了几种组合:
onStartShouldSetPanResponder | onStartShouldSetPanResponderCapture | 结果 |
---|---|---|
true | true | work |
true | false | work |
false | true | work |
false | false | not work |
这说明,只要两者有一个true,则触摸都会进入onPanResponderGrant
。网上搜索了下,也没有找到两者的区别。说实话,我对这里还是表示疑惑的,如果有读者知道原因,请指教。我目前怀疑是react-native
的bug
onMoveShouldSetPanResponder
onMoveShouldSetPanResponder
从字面上理解,也是是否可以在移动中响应。我们先将其返回false,看下效果。居然可以移动…
查了github,貌似是个bug [Touchable] How to stopPropagation touch event
还是好多bug啊,一声叹息。。。(还是我太蠢没找到???)
多层响应
我们先尝试,在红色区域下面加一个灰色的区域,而且实现上面的触摸移动效果:
代码:
import React, {PureComponent, Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
PanResponder,
} from 'react-native';
export default class TouchStartAndRelease extends PureComponent {
constructor(props) {
super(props);
this.state = {
backgroundColor: 'red',
marginTop: 100,
marginLeft: 100,
backgroundColor1: 'grey',
marginTop1: 100,
marginLeft1: 100,
};
this.lastX = this.state.marginLeft;
this.lastY = this.state.marginTop;
this.lastX1 = this.state.marginLeft1;
this.lastY1 = this.state.marginTop1;
}
componentWillMount(){
this._panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight();
console.log('highlight');
},
onPanResponderMove: (evt, gestureState) => {
console.log(`gestureState.dx : ${gestureState.dx} gestureState.dy : ${gestureState.dy}`);
this.setState({
marginLeft: this.lastX + gestureState.dx,
marginTop: this.lastY + gestureState.dy,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight();
this.lastX = this.state.marginLeft;
this.lastY = this.state.marginTop;
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
this._panResponder1 = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onMoveShouldSetPanResponder: (evt, gestureState) => {
return true;
},
onPanResponderGrant: (evt, gestureState) => {
this._highlight1();
},
onPanResponderMove: (evt, gestureState) => {
console.log(`gestureState.dx : ${gestureState.dx} gestureState.dy : ${gestureState.dy}`);
this.setState({
marginLeft1: this.lastX1 + gestureState.dx,
marginTop1: this.lastY1 + gestureState.dy,
});
},
onPanResponderRelease: (evt, gestureState) => {
this._unhighlight1();
this.lastX1 = this.state.marginLeft1;
this.lastY1 = this.state.marginTop1;
},
onPanResponderTerminate: (evt, gestureState) => {
},
});
}
_unhighlight(){
this.setState({
backgroundColor: 'red',
});
}
_highlight(){
this.setState({
backgroundColor: 'blue',
});
}
_unhighlight1(){
this.setState({
backgroundColor1: 'grey',
});
}
_highlight1(){
this.setState({
backgroundColor1: 'green',
});
}
render() {
return (
<View style={styles.container}>
<View style={
[styles.greyView,
{
backgroundColor: this.state.backgroundColor1,
marginTop: this.state.marginTop1,
marginLeft: this.state.marginLeft1,
}
]}
{...this._panResponder1.panHandlers}
>
<View style={[styles.redView,
{
backgroundColor: this.state.backgroundColor,
marginTop: this.state.marginTop,
marginLeft: this.state.marginLeft,
}
]}
{...this._panResponder.panHandlers}
></View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
greyView: {
width: 200,
height: 200,
},
redView: {
width: 100,
height: 100,
},
});
AppRegistry.registerComponent('TouchStartAndRelease', () => TouchStartAndRelease);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
看下效果:
点击红色区域,其变蓝,然后移动开始之后,底部的灰色也会变绿,移动发现,整体移动,相当于移动下面的区域。松开手后,上面的view不变回红色,下面的view变回灰色.只有单独点上面的view,而不移动,松开后其才会转成变回红色。
这是为什么呢? 我们分别在两个view的move函数中打log,发现根本没有进入上面view的move函数。这时就要介绍下上面讲到的另一个函数了:onPanResponderTerminate
,我们发现,移动的时候,进入了上面view的这个函数,说明它的控制权,被抢走了。rn的多层触摸事件,我理解是从底层挨个网上查询,看哪个view想要接收,一定被接收,则消息不再传递。
把红色view的onStartShouldSetPanResponder
和 onMoveShouldSetPanResponder
都返回false,发现点击红色区域的时候,灰色的区域也会有效果,和我们正常的理解也一样。效果如下:
多点触摸
如果是多点触摸呢?这里就要通过nativeEvent里面的touches去处理。记得,当前活跃的panResponder只有一个,所以需要在一个responder里面取处理两个触摸。