react-native使用PanResponder实现pinch手势

react-native使用PanResponder实现pinch手势

一、RN中的高级手势功能PanResponder

PanResponder类可以将多点触摸操作协调成一个手势。它使得一个单点触摸可以接受更多的触摸操作,也可以用于识别简单的多点触摸手势。

它提供了一个对触摸响应系统响应器的可预测的包装。对于每一个处理函数,它在原生事件之外提供了一个新的gestureState对象。

onPanResponderMove: (event, gestureState) => {}

其中event对象有:

  • 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 - 当前在屏幕上的有效触摸点的数量

基本用法:

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 现在会被设置为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} />
    );
  },

二、编写pinch处理

思路:通过numberActiveTouches获取手势的有效点,只处理2个手指的动作,通过touches点的集合,计算初始位置的直线距离和实时移动的直线距离,计算是放大还是缩放,使用距离作比例尺。

'use strict'

import React, { Component } from 'react'
import { View, StyleSheet, Text, PanResponder } from 'react-native'
import { Style, Const } from 'common'



export default class KLineView extends Component {
    constructor(props) {
        super(props);

        this.initDistend,

            this.state = {
                point1x: 0,
                point1y: 0,
                point2x: 0,
                point2y: 0,
                scaleNumber: 0,
            }
    }

    componentWillMount() {
        this._pinchResponder = PanResponder.create({
            onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
            onStartShouldSetPanResponderCapture: this._handleStartShouldSetPanResponderCapture,
            onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
            onMoveShouldSetPanResponderCapture: this._handleMoveShouldSetPanResponderCapture,


            onPanResponderMove: this._handlePanResponderMove,
            onPanResponderGrant: this._handlePanResponderGrant,
            onPanResponderRelease: this._handlePanResponderEnd,
            onPanResponderTerminate: this._handlePanResponderEnd,
            onPanResponderStart: this._handlePanResponderStart,
        })
    }
    componentDidMount() {


    }

    _handleStartShouldSetPanResponder = (event, gestureState) => {
        if (gestureState.numberActiveTouches == 2)   //两点手势则处理
        {
            return true;
        }
        return false;
    }
    _handleStartShouldSetPanResponderCapture = (event, gestureState) => {
        if (gestureState.numberActiveTouches == 2)   //两点手势则处理
        {
            return true;
        }
        return false;
    }
    _handleMoveShouldSetPanResponder = (event, gestureState) => {
        if (gestureState.numberActiveTouches == 2)   //两点手势则处理
        {
            return true;
        }
        return false;
    }
    _handleMoveShouldSetPanResponderCapture = (event, gestureState) => {
        if (gestureState.numberActiveTouches == 2)   //两点手势则处理
        {
            return true;
        }
        return false;
    }



    _handlePanResponderGrant = () => {

    }
    _handlePanResponderEnd = () => {

    }
    _handlePanResponderStart = (event, gestureState) => {
        if (gestureState.numberActiveTouches == 2)   //两点手势
        {
            //这里计算初始的距离 √(x1-x2)^2+(y1-y2)^2
            let distend = Math.sqrt(
                Math.pow(event.nativeEvent.touches[0].pageX - event.nativeEvent.touches[1].pageX, 2) +
                Math.pow(event.nativeEvent.touches[0].pageY - event.nativeEvent.touches[1].pageY, 2)
            )
            this.initDistend = distend;

            this.setState({
                point1x: event.nativeEvent.touches[0].pageX,
                point1y: event.nativeEvent.touches[0].pageY,
                point2x: event.nativeEvent.touches[1].pageX,
                point2y: event.nativeEvent.touches[1].pageY,
            })
        }

    }
    _handlePanResponderMove = (event, gestureState) => {
        if (gestureState.numberActiveTouches == 2)   //两点手势
        {
            let distend = Math.sqrt(
                Math.pow(event.nativeEvent.touches[0].pageX - event.nativeEvent.touches[1].pageX, 2) +
                Math.pow(event.nativeEvent.touches[0].pageY - event.nativeEvent.touches[1].pageY, 2)
            )
            let scaleNumber = distend - this.initDistend
            this.setState({
                point1x: event.nativeEvent.touches[0].pageX,
                point1y: event.nativeEvent.touches[0].pageY,
                point2x: event.nativeEvent.touches[1].pageX,
                point2y: event.nativeEvent.touches[1].pageY,
                scaleNumber: scaleNumber,

            })
        }
    }

    render() {
        return (<View style={[Style.container, { backgroundColor: 'green', }]} {...this._pinchResponder.panHandlers}>
            <Text>两点手势坐标</Text>
            <View style={{flexDirection: 'row'}}>
                <Text>缩放数值</Text>
                <Text>{this.state.scaleNumber}</Text>
            </View>
            <View style={{ flex: 1, flexDirection: 'row' }}>
                <View style={{ flex: 1 }}>
                    <Text>point1</Text>
                    <Text>x</Text>
                    <Text>{this.state.point1x}</Text>
                    <Text>y</Text>
                    <Text>{this.state.point1y}</Text>
                </View>

                <View style={{ flex: 1 }}>
                    <Text>point2</Text>
                    <Text>x</Text>
                    <Text>{this.state.point2x}</Text>
                    <Text>y</Text>
                    <Text>{this.state.point2y}</Text>
                </View>

            </View>
        </View>)
    }
}
// 默认基础样式 
var baseStyle = StyleSheet.create({
    container: {
        flex: 1,
        borderTopWidth: 1,
        borderBottomWidth: 1,
        borderColor: '#cbd2d9',
        backgroundColor: '#FFF',
    },

})

猜你喜欢

转载自blog.csdn.net/zramals/article/details/73294211