RN 原生动画 Animated 用法、动画性能优化
React Native 原生Animated是 RN 官方提供的动画库,适合实现大部分基础动画(淡入淡出、缩放、位移、旋转等)。如果是面试,通常会问两个方面:
Animated 的基本用法
动画为什么会卡?如何优化?
下面按这两个方面总结。
一、Animated 基本用法
1. 创建动画值
const fadeAnim = useRef(new Animated.Value(0)).current;Animated.Value 是动画驱动值。
例如:
0 -----> 1表示透明度从 0 到 1。
2. Animated.View
普通 View 不能绑定 Animated.Value。
必须使用:
<Animated.View style={{ opacity: fadeAnim, }} />3. timing 动画
最常见。
Animated.timing(fadeAnim, { toValue: 1, duration: 500, useNativeDriver: true, }).start();参数:
| 参数 | 作用 |
|---|---|
| toValue | 目标值 |
| duration | 动画时间 |
| easing | 缓动函数 |
| delay | 延迟 |
| useNativeDriver | 是否使用原生驱动 |
4. spring 弹簧动画
Animated.spring(scale, { toValue: 1, friction: 4, tension: 80, useNativeDriver: true, }).start();效果:
0.8 ↓ 1.1 ↓ 0.98 ↓ 1适合:
Button点击
卡片弹出
Drawer
5. decay
模拟惯性。
Animated.decay(position, { velocity: 2, deceleration: 0.998, useNativeDriver: true, }).start();一般用于:
滑动 ↓ 松手继续滑6. sequence
串行动画。
Animated.sequence([ Animated.timing(opacity,...), Animated.spring(scale,...) ]).start();执行顺序:
透明 ↓ 缩放7. parallel
并行动画。
Animated.parallel([ Animated.timing(opacity,...), Animated.spring(scale,...) ]).start();同时执行。
8. stagger
交错动画。
Animated.stagger(100, animations).start();效果:
Item1 100ms Item2 100ms Item39. loop
循环动画。
Animated.loop( Animated.timing(...) ).start();例如 Loading。
二、插值 interpolate
Animated.Value 往往只有
0~1需要转换。
例如:
const rotate = value.interpolate({ inputRange:[0,1], outputRange:["0deg","360deg"] })再绑定:
transform:[ { rotate } ]也可以:
0 ↓ 100pxtranslateX:value.interpolate({ inputRange:[0,1], outputRange:[0,100] })三、Animated.event
绑定滚动。
const scrollY = useRef(new Animated.Value(0)).current; <Animated.ScrollView onScroll={Animated.event( [{ nativeEvent:{ contentOffset:{ y:scrollY } } }], { useNativeDriver:true } )} />这样 Header 就能跟随 Scroll 做动画,而且使用原生驱动时不会因 JS 线程繁忙而明显掉帧。(React Native)
四、Animated 常见动画
例如透明:
opacity位移:
translateX translateY缩放:
scale旋转:
rotate组合:
transform:[ {translateY}, {scale}, {rotate} ]五、为什么 Animated 会卡?
RN 有:
JS Thread ↓ Bridge ↓ Native(UI Thread)如果:
JS执行太久例如:
大量计算 网络回调 render setState动画每一帧都要经过 Bridge 更新,就容易掉帧。
六、useNativeDriver 原理
默认:
JS ↓ 计算动画 ↓ Bridge ↓ Native每一帧都要跨线程。
开启:
useNativeDriver:true之后:
开始动画 ↓ 把动画配置发送给 Native ↓ Native 自己执行动画运行过程中无需每帧经过 JS,因此即使 JS 线程短暂阻塞,动画仍能保持流畅。(React Native Archive)
七、为什么 useNativeDriver 更快?
因为:
没有 Bridge 通信
以前:
60FPS ↓ 60次Bridge现在:
启动一次 ↓ Native执行Bridge 开销几乎没有。
八、useNativeDriver 的限制
只能动画:
✅
opacity transform translate scale rotate不能:
width height left top flex margin也就是说,布局属性通常不能由原生驱动直接动画。(React Native Archive)
九、动画性能优化
① 优先使用 useNativeDriver
Animated.timing(...,{ useNativeDriver:true })这是官方推荐的首选优化。(React Native)
② 少动画 Layout
不要:
width height left top推荐:
translate scale opacityGPU 对transform和opacity的处理通常更高效。(React Native Archive)
③ 避免频繁 setState
错误:
setState() ↓ render() ↓ 动画改为:
Animated.Value驱动 UI。
④ 减少组件重渲染
例如:
React.memo useMemo useCallback动画组件不要反复 Render。
⑤ Scroll 动画使用 Animated.event
不要:
onScroll={()=>{ setState() }}而是:
Animated.event(...)减少 JS 参与,提高滚动跟随动画的流畅度。(React Native Archive)
⑥ 大列表不要全部动画
例如:
FlatList 1000 Item ↓ 1000 Animation建议:
仅为可见项添加动画
配合
FlatList的虚拟化能力避免长时间运行大量循环动画
⑦ 使用 Release 包测试
Debug 模式下:
JS很慢不要拿 Debug 判断动画性能。
十、Animated 与 Reanimated 对比
| 对比项 | Animated | Reanimated |
|---|---|---|
| 官方支持 | ✅ | 第三方(社区主流) |
| 学习成本 | 低 | 较高 |
| useNativeDriver | 支持 | 默认在 UI 线程执行工作单元 |
| 手势联动 | 一般 | 很强 |
| 复杂动画 | 一般 | 优秀 |
| 性能 | 好 | 更好,尤其复杂交互场景 |
目前 React Native 社区中,如果涉及复杂手势、共享值、拖拽、布局动画等,很多项目更倾向于使用 Reanimated;而简单的透明度、位移、缩放等动画,官方Animated已经能够满足大多数需求。(SWMansion Docs)
面试总结(高频回答)
React Native 的
Animated通过Animated.Value驱动动画,可使用timing、spring、sequence、parallel、loop等 API 实现各种动画效果。性能优化的核心是尽量开启useNativeDriver,让动画在原生 UI 线程执行,减少 JS 线程和 Bridge 的参与;同时优先动画transform和opacity,避免布局属性动画,减少组件重渲染,并在滚动场景使用Animated.event绑定事件,从而获得更流畅的 60 FPS 动画体验。(React Native)