react-native-animations
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact 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-handlerbash
npm install react-native-reanimated react-native-gesture-handlerbabel.config.js
babel.config.js
module.exports = {
plugins: ['react-native-reanimated/plugin'],
};
undefinedmodule.exports = {
plugins: ['react-native-reanimated/plugin'],
};
undefined2. 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. 动画时序
| Function | Use Case |
|---|---|
| withTiming | Linear, controlled duration |
| withSpring | Natural, physics-based |
| withDecay | Momentum-based (fling) |
| withSequence | Multiple animations in order |
| withRepeat | Looping 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
常见错误与解决方案
| Error | Cause | Solution |
|---|---|---|
| "Attempted to call from worklet" | Missing runOnJS | Wrap with |
| Animation not running | Missing 'worklet' | Add 'worklet' directive |
| Gesture not working | Missing root view | Add GestureHandlerRootView |
| 错误 | 原因 | 解决方案 |
|---|---|---|
| "Attempted to call from worklet" | 缺少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-animationSkill("react-native-animations")绑定代理:
05-react-native-animation