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全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
React Native学习之PanResponder手势识别
PanResponder基本介绍 PanResponder:平底锅的响应者。PanResponder类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以……
<<上一篇
下一篇>>
文章目录
关闭
目 录