react-native-animations

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Native Animations Skill

React Native 动画技能

Learn high-performance animations using Reanimated 3, Gesture Handler, and layout animations.
学习使用Reanimated 3、Gesture Handler和布局动画创建高性能动画。

Prerequisites

前置要求

  • React Native basics
  • Understanding of JavaScript closures
  • Familiarity with transforms and styles
  • React Native基础知识
  • 理解JavaScript闭包
  • 熟悉变换和样式

Learning Objectives

学习目标

After completing this skill, you will be able to:
  • Create smooth 60fps animations with Reanimated
  • Handle complex gestures with Gesture Handler
  • Implement layout entering/exiting animations
  • Optimize animations for performance
  • Combine gestures with animations

完成本技能学习后,你将能够:
  • 使用Reanimated创建流畅的60fps动画
  • 使用Gesture Handler处理复杂手势
  • 实现布局进入/退出动画
  • 优化动画性能
  • 将手势与动画结合

Topics Covered

涵盖主题

1. Installation

1. 安装

bash
npm install react-native-reanimated react-native-gesture-handler
bash
npm install react-native-reanimated react-native-gesture-handler

babel.config.js

babel.config.js

module.exports = { plugins: ['react-native-reanimated/plugin'], };
undefined
module.exports = { plugins: ['react-native-reanimated/plugin'], };
undefined

2. Reanimated Basics

2. Reanimated 基础

tsx
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';

function AnimatedBox() {
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePress = () => {
    scale.value = withSpring(scale.value === 1 ? 1.5 : 1);
  };

  return (
    <Pressable onPress={handlePress}>
      <Animated.View style={[styles.box, animatedStyle]} />
    </Pressable>
  );
}
tsx
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';

function AnimatedBox() {
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePress = () => {
    scale.value = withSpring(scale.value === 1 ? 1.5 : 1);
  };

  return (
    <Pressable onPress={handlePress}>
      <Animated.View style={[styles.box, animatedStyle]} />
    </Pressable>
  );
}

3. Gesture Handler

3. Gesture Handler

tsx
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

function DraggableBox() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  const pan = Gesture.Pan()
    .onUpdate((e) => {
      translateX.value = e.translationX;
      translateY.value = e.translationY;
    })
    .onEnd(() => {
      translateX.value = withSpring(0);
      translateY.value = withSpring(0);
    });

  const style = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value },
      { translateY: translateY.value },
    ],
  }));

  return (
    <GestureDetector gesture={pan}>
      <Animated.View style={[styles.box, style]} />
    </GestureDetector>
  );
}
tsx
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

function DraggableBox() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  const pan = Gesture.Pan()
    .onUpdate((e) => {
      translateX.value = e.translationX;
      translateY.value = e.translationY;
    })
    .onEnd(() => {
      translateX.value = withSpring(0);
      translateY.value = withSpring(0);
    });

  const style = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value },
      { translateY: translateY.value },
    ],
  }));

  return (
    <GestureDetector gesture={pan}>
      <Animated.View style={[styles.box, style]} />
    </GestureDetector>
  );
}

4. Layout Animations

4. 布局动画

tsx
import Animated, { FadeIn, FadeOut, Layout } from 'react-native-reanimated';

function AnimatedList({ items }) {
  return (
    <Animated.View layout={Layout.springify()}>
      {items.map((item) => (
        <Animated.View
          key={item.id}
          entering={FadeIn}
          exiting={FadeOut}
          layout={Layout.springify()}
        >
          <Text>{item.title}</Text>
        </Animated.View>
      ))}
    </Animated.View>
  );
}
tsx
import Animated, { FadeIn, FadeOut, Layout } from 'react-native-reanimated';

function AnimatedList({ items }) {
  return (
    <Animated.View layout={Layout.springify()}>
      {items.map((item) => (
        <Animated.View
          key={item.id}
          entering={FadeIn}
          exiting={FadeOut}
          layout={Layout.springify()}
        >
          <Text>{item.title}</Text>
        </Animated.View>
      ))}
    </Animated.View>
  );
}

5. Animation Timing

5. 动画时序

FunctionUse Case
withTimingLinear, controlled duration
withSpringNatural, physics-based
withDecayMomentum-based (fling)
withSequenceMultiple animations in order
withRepeatLooping animations

函数使用场景
withTiming线性、可控时长
withSpring自然、基于物理特性
withDecay基于动量(甩动)
withSequence按顺序执行多个动画
withRepeat循环动画

Quick Start Example

快速开始示例

tsx
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  interpolate,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

function SwipeCard() {
  const translateX = useSharedValue(0);

  const gesture = Gesture.Pan()
    .onUpdate((e) => { translateX.value = e.translationX; })
    .onEnd(() => { translateX.value = withSpring(0); });

  const style = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value },
      { rotate: `${interpolate(translateX.value, [-200, 200], [-15, 15])}deg` },
    ],
  }));

  return (
    <GestureDetector gesture={gesture}>
      <Animated.View style={[styles.card, style]} />
    </GestureDetector>
  );
}

tsx
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  interpolate,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

function SwipeCard() {
  const translateX = useSharedValue(0);

  const gesture = Gesture.Pan()
    .onUpdate((e) => { translateX.value = e.translationX; })
    .onEnd(() => { translateX.value = withSpring(0); });

  const style = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value },
      { rotate: `${interpolate(translateX.value, [-200, 200], [-15, 15])}deg` },
    ],
  }));

  return (
    <GestureDetector gesture={gesture}>
      <Animated.View style={[styles.card, style]} />
    </GestureDetector>
  );
}

Common Errors & Solutions

常见错误与解决方案

ErrorCauseSolution
"Attempted to call from worklet"Missing runOnJSWrap with
runOnJS()
Animation not runningMissing 'worklet'Add 'worklet' directive
Gesture not workingMissing root viewAdd GestureHandlerRootView

错误原因解决方案
"Attempted to call from worklet"缺少runOnJS使用
runOnJS()
包裹
动画未运行缺少'worklet'指令添加'worklet'指令
手势不生效缺少根视图添加GestureHandlerRootView

Validation Checklist

验证清单

  • Animations run at 60fps
  • Gestures respond smoothly
  • No frame drops on low-end devices
  • Layout animations don't cause jank

  • 动画以60fps运行
  • 手势响应流畅
  • 在低端设备上无掉帧
  • 布局动画无卡顿

Usage

使用方法

Skill("react-native-animations")
Bonded Agent:
05-react-native-animation
Skill("react-native-animations")
绑定代理
05-react-native-animation