React Native学习之PanResponder手势识别
PanResponder基本介绍
PanResponder:平底锅的响应者。PanResponder类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。
React Native 框架底层的手势响应系统提供了响应处理器,PanResponder将这些手势响应处理器再次进行封装,以便开发者更容易对手势进行处理,更容易预测用户的手势,对每一个手势响应处理器,PanResponder除了为其提供代表触摸行为的原生事件外,还提供了一个新的手势状态对象用来详细描述手势的状态。
PanResponder的基本思想是:监视屏幕上指定大小、位置的矩形区域,当用手指按压这个区域中的某点后,系统会收到这个事件,当按压后拖动手指时,会收到手势引发的各类事件,当手指离开这个矩形区域时,开发者也会收到相应的事件。
注意:开发者可以任意指定监视矩形区域的大小,但在这个区域里,只有第一个按下的事件会上报和继续监视处理,如果第一个手指按下还没有离开,接着第二个手指又来按下了,那么对第二个手指的各种触摸事件无法捕获。
注意:开发者可以在屏幕上指定多个监视矩形区域,但是不能同时监视多个矩形区域的不同触摸事件。
注意:监视区域会阻止被监视区域覆盖的组件接收触摸事件,比如监视区域覆盖了一个按钮,那么就无法通过点击这个按钮来触发其对应的事件,只能在PanResponder监视器的事件处理中对触摸行为进行处理
利用PanResponder实现监视器的步骤
(1)指定监视区域
如果监视区域有多个,一定不能重叠,否则都失效
(2)定义监视器相关变量
指向监视器的变量(必须有)、指向监视器监视区域的变量(可以有)、记录监视区域左上角顶点坐标的两个数值变量(可以有)、上一次触摸点的横纵坐标变量(可以有)
(3)准备监视器的事件处理函数(13个)
(4)建立监视器(PanResponder.create
)
(5)将监视器与监视区域关联 {% raw %}{...this.watcher.panHandlers}{% endraw %}
一个手势对象 gestureState 包含的字段
stateID
- 触摸状态的ID。在屏幕上至少有一个触摸点的情况下,这个ID会一直有效。moveX
- 最近一次移动时的屏幕横坐标moveY
- 最近一次移动时的屏幕纵坐标x0
- 当响应器产生时的屏幕坐标y0
- 当响应器产生时的屏幕坐标dx
- 从触摸操作开始时的累计横向路程dy
- 从触摸操作开始时的累计纵向路程vx
- 当前的横向移动速度vy
- 当前的纵向移动速度numberActiveTouches
- 当前在屏幕上的有效触摸点的数量
手势操作实例
点击、拖动选择百分百参数,比如说播放器的音量大小。
index.android.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
PanResponder,
ProgressBarAndroid,
View
} from 'react-native';
import Dimensions from 'Dimensions';
let totalWidth = Dimensions.get('window').width;
class RNAPP extends Component {
constructor(props) {
super(props);
this.state = {
progress: 0,
}
}
componentWillMount() {
this.watcher = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: this._onPanResponderGrant, //处理按下的事件
onPanResponderMove: this._onPanResponderMove, //处理移动的事件
});
}
_onPanResponderGrant = (event, gestureState) => {
let touchPonitX = gestureState.x0; //获取触摸点的横坐标
let progress;
if (touchPonitX < 20)
progress = 0;
else {
if (touchPonitX > (totalWidth - 20))
progress = 1;
else
progress = (touchPonitX - 20) / (totalWidth - 40);
}
this.setState({ progress });
}
_onPanResponderMove = (event, gestureState) => {
let touchPonitX = gestureState.moveX;
let progress;
if (touchPonitX < 20)
progress = 0;
else {
if (touchPonitX > (totalWidth - 20))
progress = 1;
else
progress = (touchPonitX - 20) / (totalWidth - 40);
}
this.setState({ progress });
}
render() {
return (
<View style={styles.container}>
<ProgressBarAndroid
styleAttr='Horizontal'
indeterminate={false}
style={styles.ProgressViewStyle}
progress={this.state.progress}
/>
<Text style={styles.textStyle}>进度:{Math.round(this.state.progress * 100) }%</Text>
//手势监视区域
<View style={styles.touchViewStyle}
{...this.watcher.panHandlers}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
ProgressViewStyle: {
width: totalWidth - 40,
left: 20,
top: 50,
},
touchViewStyle: {
width: totalWidth - 20,
height: 40,
backgroundColor: 'transparent',
position: 'absolute',
left: 10,
top: 32,
},
textStyle: {
fontSize: 30,
left: 20,
top: 70,
},
});
AppRegistry.registerComponent('RNAPP', () => RNAPP);
index.ios.js
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
PanResponder,
ProgressViewIOS,
View
} from 'react-native';
import Dimensions from 'Dimensions';
let totalWidth = Dimensions.get('window').width;
class RNAPP extends Component {
constructor(props) {
super(props);
this.state = {
progress: 0,
}
}
componentWillMount() {
this.watcher = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: this._onPanResponderGrant, //处理按下的事件
onPanResponderMove: this._onPanResponderMove, //处理移动的事件
});
}
_onPanResponderGrant = (event, gestureState) => {
let touchPonitX = gestureState.x0;
let progress;
if (touchPonitX < 20)
progress = 0;
else {
if (touchPonitX > (totalWidth - 20))
progress = 1;
else
progress = (touchPonitX - 20) / (totalWidth - 40);
}
this.setState({ progress });
}
_onPanResponderMove = (event, gestureState) => {
let touchPonitX = gestureState.moveX;
let progress;
if (touchPonitX < 20)
progress = 0;
else {
if (touchPonitX > (totalWidth - 20))
progress = 1;
else
progress = (touchPonitX - 20) / (totalWidth - 40);
}
this.setState({ progress });
}
render() {
return (
<View style={styles.container}>
<ProgressViewIOS
style={styles.ProgressViewStyle}
progress={this.state.progress}
/>
<Text style={styles.textStyle}>进度:{Math.round(this.state.progress * 100) }%</Text>
//手势监视区域
<View style={styles.touchViewStyle}
{...this.watcher.panHandlers} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
ProgressViewStyle: {
width: totalWidth - 40,
left: 20,
top: 50,
},
touchViewStyle: {
width: totalWidth - 20,
height: 40,
backgroundColor: 'transparent',
position: 'absolute',
left: 10,
top: 32,
},
textStyle: {
fontSize: 30,
left: 20,
top: 70,
},
});
AppRegistry.registerComponent('RNAPP', () => RNAPP);
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/react-native-learning-panresponder-gesture-recognition/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论