Bootstrap

React Native 全栈开发实战班 - 用户界面之手势系统应用

在移动应用中,手势交互 是提升用户体验的重要手段。通过手势,用户可以更直观、自然地与应用进行交互。React Native 提供了强大的手势处理系统,允许开发者轻松实现各种手势操作,如滑动、缩放、旋转等。本章节将详细介绍 React Native 中的手势系统,包括如何使用内置的 PanResponderGesture Responder System,以及如何使用第三方库(如 react-native-gesture-handler)实现更复杂的手势交互。


2.1 手势系统概述

在 React Native 中,手势系统主要由以下两个部分组成:

  1. Gesture Responder System(手势响应系统): 负责处理触摸事件,确定哪个组件应该响应手势。
  2. PanResponder: 基于 Gesture Responder System,提供更高级的手势处理功能,支持多点触控和手势识别。

React Native 还提供了第三方库 react-native-gesture-handler,用于实现更复杂和高效的手势交互。


2.2 使用 PanResponder

PanResponder 是 React Native 提供的一个高级手势处理 API,基于 Gesture Responder System 构建。它可以处理多种手势事件,如 onMoveShouldSetPanResponder, onPanResponderMove, onPanResponderRelease 等。

2.2.1 基本用法

步骤:

  1. 创建 PanResponder:

    使用 PanResponder.create 创建一个 PanResponder 对象,并定义手势处理函数。

    const panResponder = useRef(
      PanResponder.create({
        onStartShouldSetPanResponder: (evt, gestureState) => true,
        onPanResponderMove: (evt, gestureState) => {
          // 处理手势移动
        },
        onPanResponderRelease: (evt, gestureState) => {
          // 处理手势释放
        },
      })
    ).current;
    
  2. 绑定 PanResponder 到组件:

    将 PanResponder 的事件处理器绑定到组件的 onStartShouldSetPanResponder, onPanResponderMove, onPanResponderRelease 等属性。

    <View {...panResponder.panHandlers} style={styles.box}>
      {/* 内容 */}
    </View>
    

示例:

// DraggableBox.js
import React, { useRef } from 'react';
import { View, Text, StyleSheet, PanResponder, Animated } from 'react-native';

const DraggableBox = () => {
  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event(
        [
          null,
          {
            dx: pan.x, // 横轴移动距离
            dy: pan.y, // 纵轴移动距离
          },
        ],
        { useNativeDriver: false }
      ),
      onPanResponderRelease: () => {
        Animated.spring(pan, {
          toValue: { x: 0, y: 0 },
          useNativeDriver: false,
        }).start();
      },
    })
  ).current;

  return (
    <View style={styles.container}>
      <Animated.View
        {...panResponder.panHandlers}
        style={[
          styles.box,
          {
            transform: [{ translateX: pan.x }, { translateY: pan.y }],
          },
        ]}
      >
        <Text style={styles.text}>Drag Me!</Text>
      </Animated.View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  box: {
    width: 200,
    height: 200,
    backgroundColor: '#f0f0f0',
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 10,
  },
  text: {
    fontSize: 18,
  },
});

export default DraggableBox;

解释:

  • Animated.event 将手势移动事件绑定到 pan 动画值。
  • onPanResponderRelease 使用 Animated.spring 实现回弹动画。
2.2.2 多点触控

PanResponder 支持多点触控,可以处理多个手指同时操作。

示例:

// MultiTouchBox.js
import React, { useRef } from 'react';
import { View, Text, StyleSheet, PanResponder, Animated } from 'react-native';

const MultiTouchBox = () => {
  const scale = useRef(new Animated.Value(1)).current;
  const pan = useRef(new Animated.ValueXY()).current;

  const panResponder = useRef(
    PanResponder.create({
      onStartShouldSetPanResponder: () => true,
      onPanResponderMove: Animated.event(
        [
          null,
          {
            dx: pan.x,
            dy: pan.y,
            scale: scale,
          },
        ],
        { useNativeDriver: false }
      ),
      onPanResponderRelease: () => {
        Animated.spring(scale, {
          toValue: 1,
          useNativeDriver: false,
        }).start();
        Animated.spring(pan, {
          toValue: { x: 0, y: 0 },
          useNativeDriver: false,
        }).start();
      },
    })
  ).current;

  return (
    <View style={styles.container}>
      <Animated.View
        {...panResponder.panHandlers}
        style={[
          styles.box,
          {
            transform: [{ translateX: pan.x }, { translateY: pan.y }, { scale }],
          },
        ]}
      >
        <Text style={styles.text}>Multi-Touch!</Text>
      </Animated.View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  box: {
    width: 200,
    height: 200,
    backgroundColor: '#f0f0f0',
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 10,
  },
  text: {
    fontSize: 18,
  },
});

export default MultiTouchBox;

解释:

  • 通过 scale 动画值实现缩放效果。
  • 支持多点触控,实现缩放和拖拽。

2.3 使用 react-native-gesture-handler

react-native-gesture-handler 是一个功能强大的手势处理库,支持更复杂的手势交互,如滑动、缩放、旋转等。

2.3.1 安装 react-native-gesture-handler
npm install react-native-gesture-handler
2.3.2 基本用法

示例:

// SwipeableCard.js
import React from 'react';
import { View, Text, StyleSheet, Animated } from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';

const SwipeableCard = () => {
  const translateX = React.useRef(new Animated.Value(0)).current;

  const onGestureEvent = Animated.event(
    [{ nativeEvent: { translationX: translateX } }],
    { useNativeDriver: true }
  );

  const onHandlerStateChange = (event) => {
    if (event.nativeEvent.state === State.END) {
      if (translateX._value > 100) {
        Animated.timing(translateX, {
          toValue: 300,
          duration: 300,
          useNativeDriver: true,
        }).start();
      } else {
        Animated.timing(translateX, {
          toValue: 0,
          duration: 300,
          useNativeDriver: true,
        }).start();
      }
    }
  };

  return (
    <View style={styles.container}>
      <PanGestureHandler onGestureEvent={onGestureEvent} onHandlerStateChange={onHandlerStateChange}>
        <Animated.View style={[styles.card, { transform: [{ translateX }] }]}>
          <Text style={styles.text}>Swipe Me!</Text>
        </Animated.View>
      </PanGestureHandler>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  card: {
    width: 200,
    height: 200,
    backgroundColor: '#f0f0f0',
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 10,
  },
  text: {
    fontSize: 18,
  },
});

export default SwipeableCard;

解释:

  • PanGestureHandler 处理滑动手势。
  • Animated.event 将手势事件绑定到 translateX 动画值。
  • 根据滑动距离实现卡片滑动效果。
2.3.3 高级用法

react-native-gesture-handler 支持多种手势识别器,如 PinchGestureHandler, RotationGestureHandler, TapGestureHandler 等。

作者简介

前腾讯电子签的前端负责人,现 whentimes tech CTO,专注于前端技术的大咖一枚!一路走来,从小屏到大屏,从 Web 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!

温馨提示:可搜老码小张公号联系导师

;