动画(Animated)
Animated 库旨在使动画构建流畅、高效且轻松维护。Animated 关注输入与输出之间的声明式关系,中间可配置的变换,以及用于控制基于时间的动画执行的 start/stop 方法。
创建动画的核心流程是创建一个 Animated.Value,将其连接到动画组件的一个或多个样式属性上,然后通过使用 Animated.timing() 来驱动动画更新。
不要直接修改动画值。你可以使用 useRef Hook 返回一个可变的 ref 对象,该对象的 current 属性会被初始化为给定参数并在组件整个生命周期内保持不变。
示例
下面的示例包含一个 View,它将基于动画值 fadeAnim 进行淡入和淡出。
请参阅 动画 指南,查看更多 Animated 的应用示例。
概述
你可以使用 Animated 的两种值类型:
Animated.Value()用于单个值Animated.ValueXY()用于二维向量
Animated.Value 可以绑定到样式属性或其他属性,并且可以进行插值。一个单一的 Animated.Value 可以驱动任意数量的属性。
配置动画
Animated 提供三种动画类型。每种动画类型提供特定的动画曲线,控制值从初始值到最终值的动画变化:
Animated.decay()从初速度开始,逐渐减速至停止。Animated.spring()提供基本的弹簧物理模型。Animated.timing()使用缓动函数随时间对值进行动画。
在大多数情况下,你会使用 timing()。默认情况下,它使用对称的 easeInOut 曲线,模拟物体逐渐加速到最大速度,然后逐渐减速停止的过程。
使用动画
动画通过调用动画对象的 start() 启动。start() 接受一个完成回调函数,当动画执行完毕时调用。如果动画正常结束,回调会接收到 {finished: true}。如果动画是因为调用了 stop()(例如被手势或另一个动画中断)而提前结束,回调会接收到 {finished: false}。
Animated.timing({}).start(({finished}) => {
/* 完成回调 */
});
使用原生驱动
使用原生驱动时,动画的所有信息会先发送到原生层,然后由原生代码在 UI 线程执行动画,无需在每一帧都通过桥接调用 JS线程。这样动画启动后,即使 JS 线程被阻塞,也不会影响动画表现。
你可以通过在动画配置中指定 useNativeDriver: true 来使用原生驱动。更多信息可见 动画 指南。
可动画组件
只有可动画组件才能被动画化。这些组件负责将动画值绑定到属性,并进行针对性的原生更新,避免每帧都进行 React 的渲染和协调过程。它们还会在卸载时进行清理,默认情况下是安全的。
createAnimatedComponent()可用于使组件支持动画。
Animated 通过上述包装导出以下可动画组件:
Animated.ImageAnimated.ScrollViewAnimated.TextAnimated.ViewAnimated.FlatListAnimated.SectionList
组合动画
动画也可以通过组合函数以复杂的方式组合:
Animated.delay()延迟一段时间后启动动画。Animated.parallel()同时启动多个动画。Animated.sequence()按顺序启动动画,等待一个完成后再启动下一个。Animated.stagger()按顺序启动动画,且各动画间有延迟,实现错落效果。
动画还可以通过将一个动画的 toValue 设置为另一个 Animated.Value 实现链式动画。更多请参见动画指南中 动态值跟踪。
默认情况下,如果其中一个动画被停止或中断,组内所有动画都会停止。
组合动画值
你可以通过加、减、乘、除或取模操作将两个动画值组合成为新的动画值:
插值
interpolate() 函数允许将输入范围映射到不同的输出范围。默认情况下,会对超出范围的值进行外推,也可以设置为限制输出值。默认使用线性插值,也支持缓动函数。
更多插值内容请见 动画 指南。
处理手势和其他事件
手势(如平移或滚动)和其他事件可通过 Animated.event() 直接映射到动画值。该方法使用结构化映射语法,从复杂事件对象中提取值。第一层是数组,支持映射多个参数,数组中包含嵌套对象。
例如,处理横向滚动手势时,可以将 event.nativeEvent.contentOffset.x 映射给 scrollX(一个 Animated.Value):
onScroll={Animated.event(
// scrollX = e.nativeEvent.contentOffset.x
[{nativeEvent: {
contentOffset: {
x: scrollX
}
}
}]
)}
参考
方法
当传入的是 ValueXY 而非 Value 时,每个配置选项可为形式为 {x: ..., y: ...} 的向量,而非标量。
decay()
static decay(value, config): CompositeAnimation;
根据衰减系数,从初始速度开始使值动画到零。
配置对象可用选项:
velocity:初速度。必填。deceleration:衰减率。默认 0.997。isInteraction:此动画是否创建InteractionManager的“交互句柄”。默认 true。useNativeDriver:是否使用原生驱动。必填。
timing()
static timing(value, config): CompositeAnimation;
沿定时缓动曲线对值进行动画。Easing 模块内置大量预设的曲线,也可自定义函数。
配置对象可用选项:
duration:动画时长(毫秒)。默认 500。easing:缓动函数定义曲线。默认是Easing.inOut(Easing.ease)。delay:动画开始前延迟(毫秒)。默认 0。isInteraction:此动画是否创建InteractionManager的“交互句柄”。默认 true。useNativeDriver:是否使用原生驱动。必填。
spring()
static spring(value, config): CompositeAnimation;
基于 阻尼谐振动 的解析弹簧模型,使值动画。追踪速度状态,以支持平滑运动和对 toValue 更新的连续响应,并可链式调用。
配置对象可用选项说明:
你只能定义以下三组参数中的一组,不能多组同时定义:
- 弹性/速度(bounciness/speed)
- 张力/摩擦(tension/friction)
- 刚度/阻尼/质量(stiffness/damping/mass)
张力/摩擦或弹性/速度选项对应于 Facebook Pop、Rebound、Origami 中的弹簧模型。
friction: 控制反弹/超越量。默认 7。tension: 控制速度。默认 40。speed: 控制动画速度。默认 12。bounciness: 控制弹性。默认 8。
指定刚度/阻尼/质量参数时,Animated.spring 使用基于阻尼谐振动运动方程的解析弹簧模型。此行为更精确,物理表现更逼真,类似 iOS 的 CASpringAnimation 实现。
stiffness: 弹簧刚度系数。默认 100。damping: 弹簧运动的摩擦阻尼。默认 10。mass: 附着弹簧末端物体的质量。默认 1。
其他配置选项:
velocity: 物体的初始速度。默认 0(静止)。overshootClamping: 是否禁止反弹。默认 false。restDisplacementThreshold: 定义弹簧被视为静止时的位移阈值。默认 0.001。restSpeedThreshold: 弹簧被视为静止时的速度阈值(单位:像素/秒)。默认 0.001。delay: 动画开始延迟(毫秒)。默认 0。isInteraction: 是否创建InteractionManager的“交互句柄”。默认 true。useNativeDriver: 是否使用原生驱动。必填。
add()
static add(a: Animated, b: Animated): AnimatedAddition;
创建一个新的动画值,由两个动画值相加组成。
subtract()
static subtract(a: Animated, b: Animated): AnimatedSubtraction;
创建一个新的动画值,由第一个动画值减去第二个动画值组成。
divide()
static divide(a: Animated, b: Animated): AnimatedDivision;
创建一个新的动画值,由第一个动画值除以第二个动画值组成。
multiply()
static multiply(a: Animated, b: Animated): AnimatedMultiplication;
创建一个新的动画值,由两个动画值相乘组成。
modulo()
static modulo(a: Animated, modulus: number): AnimatedModulo;
创建一个新的动画值,为提供的动画值的(非负)取模值。
diffClamp()
static diffClamp(a: Animated, min: number, max: number): AnimatedDiffClamp;
创建一个新的动画值,限制在两个值之间。它使用上一个值的差分,即使当前值远离边界,也会在值开始靠近边界时才改变。(value = clamp(value + diff, min, max))
此方法在滚动事件中非常有用,例如,向上滚动显示导航栏,向下滚动隐藏导航栏。
delay()
static delay(time: number): CompositeAnimation;
延迟指定时间后启动动画。
sequence()
static sequence(animations: CompositeAnimation[]): CompositeAnimation;
顺序启动一组动画,等待上一个完成后再启动下一个。如果当前运行的动画被停止,则后续动画不再启动。
parallel()
static parallel(
animations: CompositeAnimation[],
config?: ParallelConfig
): CompositeAnimation;
同时启动一组动画。默认情况下,若其中一个动画停止,所有动画都会停止。可以通过 stopTogether 标志覆盖此行为。
stagger()
static stagger(
time: number,
animations: CompositeAnimation[]
): CompositeAnimation;
组内动画可以重叠执行,但依次启动且启动时间有间隔。适合实现拖尾效果。
loop()
static loop(
animation: CompositeAnimation[],
config?: LoopAnimationConfig
): CompositeAnimation;
无限循环给定的动画,每次结束后重置并重新开始。如果子动画设置为 useNativeDriver: true,循环将不会阻塞 JS 线程。此外,循环动画可防止基于 VirtualizedList 的组件在动画运行时渲染更多行。你可以在子动画配置中传入 isInteraction: false 来避免该问题。
配置对象可用选项:
iterations: 动画循环次数。默认-1(无限循环)。
event()
static event(
argMapping: Mapping[],
config?: EventConfig
): (...args: any[]) => void;
接收映射数组,根据映射从每个参数中提取值,并调用映射输出的 setValue。例如:
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: this._scrollX}}}],
{listener: (event: ScrollEvent) => console.log(event)}, // 可选异步监听器
)}
...
onPanResponderMove: Animated.event(
[
null, // 忽略原始事件参数
{dx: this._panX},
], // gestureState 参数
{
listener: (
event: GestureResponderEvent,
gestureState: PanResponderGestureState
) => console.log(event, gestureState),
} // 可选异步监听器
);
配置对象可用选项:
listener: 可选异步监听器。useNativeDriver: 是否使用原生驱动。必填。
forkEvent()
static forkEvent(event: AnimatedEvent, listener: Function): AnimatedEvent;
高级命令式 API,用于在通过属性传入的动画事件上侦查。允许向已存在的 AnimatedEvent 添加新的 JS 监听器。如果 animatedEvent 本身就是 JS 监听器,将两个监听器合并为一个;如果 animatedEvent 为 null/undefined,直接赋值为 JS 监听器。建议尽可能直接使用值。
unforkEvent()
static unforkEvent(event: AnimatedEvent, listener: Function);
start()
static start(callback?: (result: {finished: boolean}) => void);
通过调用 start() 启动动画。start() 接受一个完成回调,该回调会在动画结束时调用,或在动画被调用 stop() 而提前终止时调用。
参数:
| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| callback | (result: {finished: boolean}) => void | 否 | 动画正常完成或因调用 stop() 而提前结束时调用的函数 |
包含回调的启动示例:
Animated.timing({}).start(({finished}) => {
/* 完成回调 */
});
stop()
static stop();
停止正在运行的动画。
reset()
static reset();
停止正在运行的动画,并将值重置为初始值。
属性
Value
用于驱动动画的标准值类。通常使用 useAnimatedValue(0); 或在类组件中使用 new Animated.Value(0); 初始化。
你可以在单独的页面了解更多关于 Animated.Value 的 API。
ValueXY
用于驱动二维动画(如平移手势)的值类。
你可以在单独的页面了解更多关于 Animated.ValueXY 的 API。
Interpolation
导出以用于 Flow 中的 Interpolation 类型。
Node
导出用于类型检查。所有动画值均继承自此类。
createAnimatedComponent
使任意 React 组件变得可动画。用于创建 Animated.View 等。
attachNativeEvent
命令式 API,用于将动画值绑定到视图的事件。尽可能优先使用带 useNativeDriver: true 的 Animated.event。