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

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

相关推荐
screct_demo3 小时前
詳細講一下在RN(ReactNative)中,6個比較常用的組件以及詳細的用法
javascript·react native·react.js
不惑_10 小时前
深度学习 · 手撕 DeepLearning4J ,用Java实现手写数字识别 (附UI效果展示)
java·深度学习·ui
光头程序员11 小时前
grid 布局react组件可以循数据自定义渲染某个数据 ,或插入某些数据在某个索引下
javascript·react.js·ecmascript
limit for me11 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架
浏览器爱好者11 小时前
如何构建一个简单的React应用?
前端·react.js·前端框架
Хайде12 小时前
Qt Desiogn生成的ui文件转化为h文件
ui
VillanelleS14 小时前
React进阶之高阶组件HOC、react hooks、自定义hooks
前端·react.js·前端框架
傻小胖15 小时前
React 中hooks之useInsertionEffect用法总结
前端·javascript·react.js
资深设备全生命周期管理19 小时前
以Python 做服务器,N Robot 做客户端,小小UI,拿捏
服务器·python·ui
iks32521 小时前
ui文件转py程序的工具
ui