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 对象,并定义手势处理函数。

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

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

    javascript 复制代码
    <View {...panResponder.panHandlers} style={styles.box}>
      {/* 内容 */}
    </View>

示例:

javascript 复制代码
// 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 支持多点触控,可以处理多个手指同时操作。

示例:

javascript 复制代码
// 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
bash 复制代码
npm install react-native-gesture-handler
2.3.2 基本用法

示例:

javascript 复制代码
// 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 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!

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

相关推荐
前端小小王38 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发1 小时前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
不是鱼5 小时前
构建React基础及理解与Vue的区别
前端·vue.js·react.js
飞翔的渴望8 小时前
antd3升级antd5总结
前端·react.js·ant design
╰つ゛木槿12 小时前
深入了解 React:从入门到高级应用
前端·react.js·前端框架
~央千澈~13 小时前
优雅草央千澈-关于蓝湖如何快速的标注交互原型是如何使用的-如何使用蓝湖设计交互原型和整个软件项目的流程逻辑-实践项目详细说明
ui·交互·蓝湖
用户305875848912515 小时前
Connected-react-router核心思路实现
react.js
军训猫猫头17 小时前
20.抽卡只有金,带保底(WPF) C#
ui·c#·wpf
wuningw19 小时前
ant-design-ui的Select选择器多选时同时获取label与vaule值
ui·arcgis
SoraLuna1 天前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos