Animated
Animated
库旨在使动画流畅、强大且易于构建和维护。Animated
专注于输入和输出之间的声明式关系、中间的可配置转换,以及用于控制基于时间的动画执行的 start
和 stop
方法。
创建动画的核心流程是创建一个 Animated.Value
,将其关联到动画组件的一个或多个样式属性,然后使用 Animated.timing()
通过动画驱动更新。
不要直接修改动画值。你可以使用
useRef Hook
来返回一个可变的 ref 对象。该 ref 对象的current
属性被初始化为给定的参数,并在组件的整个生命周期中持续存在。
示例
以下示例包含一个将根据动画值 fadeAnim
淡入淡出的 View
。
请参阅动画指南以查看更多实际应用中的 Animated
示例。
概述
有两种值类型可以与 Animated
一起使用:
Animated.Value()
用于单个值。Animated.ValueXY()
用于矢量值。
Animated.Value
可以绑定到样式属性或其他 props,也可以进行插值。单个 Animated.Value
可以驱动任意数量的属性。
配置动画
Animated
提供了三种动画类型。每种动画类型都提供特定的动画曲线,用于控制你的值如何从初始值动画到最终值。
Animated.decay()
从初始速度开始,逐渐减速至停止。Animated.spring()
提供基本的弹簧物理模型。Animated.timing()
使用缓动函数随时间动画一个值。
在大多数情况下,你将使用 timing()
。默认情况下,它使用对称的 easeInOut 曲线,这种曲线表现了物体逐渐加速到全速,然后逐渐减速到停止的过程。
处理动画
通过在动画上调用 start()
来启动动画。start()
接受一个完成回调函数,该函数将在动画完成时被调用。如果动画正常运行结束,完成回调函数将接收到 {finished: true}
。如果动画因在其完成前调用了 stop()
而结束(例如,被手势或其他动画打断),则将接收到 {finished: false}
。
Animated.timing({}).start(({finished}) => {
/* completion callback */
});
使用原生驱动
通过使用原生驱动,我们在启动动画之前将动画的所有信息发送到原生层,允许原生代码在 UI 线程上执行动画,而无需在每一帧都经过桥接。一旦动画开始,即使 JS 线程被阻塞,也不会影响动画。
你可以通过在动画配置中指定 useNativeDriver: true
来使用原生驱动。请参阅动画指南了解更多。
可动画组件
只有可动画组件才能进行动画处理。这些特殊的组件能够神奇地将动画值绑定到属性,并执行有针对性的原生更新,以避免每一帧都经过 React 渲染和协调过程的开销。它们还在卸载时处理清理工作,因此默认是安全的。
createAnimatedComponent()
可用于使组件可动画化。
Animated
使用上述包装器导出了以下可动画组件:
Animated.Image
Animated.ScrollView
Animated.Text
Animated.View
Animated.FlatList
Animated.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;
根据衰减系数,将值从初始速度动画到零。
Config 是一个对象,可能包含以下选项:
velocity
:初始速度。必需。deceleration
:衰减率。默认值为 0.997。isInteraction
:此动画是否在InteractionManager
上创建一个“交互句柄”。默认为 true。useNativeDriver
:为 true 时使用原生驱动。必需。
timing()
static timing(value, config): CompositeAnimation;
沿定时缓动曲线动画一个值。Easing
模块有大量的预定义曲线,你也可以使用自己的函数。
Config 是一个对象,可能包含以下选项:
duration
:动画时长(毫秒)。默认值为 500。easing
:定义曲线的缓动函数。默认值为Easing.inOut(Easing.ease)
。delay
:延迟(毫秒)后开始动画。默认值为 0。isInteraction
:此动画是否在InteractionManager
上创建一个“交互句柄”。默认为 true。useNativeDriver
:为 true 时使用原生驱动。必需。
spring()
static spring(value, config): CompositeAnimation;
根据基于阻尼谐振的解析弹簧模型动画一个值。跟踪速度状态,以便在 toValue
更新时创建流畅的运动,并且可以串联。
Config 是一个对象,可能包含以下选项。
请注意,你只能定义 bounciness/speed、tension/friction 或 stiffness/damping/mass 中的一个,不能定义多个。
friction/tension 或 bounciness/speed 选项与 Facebook Pop
、Rebound 和 Origami 中的弹簧模型匹配。
friction
:控制“弹性”/过冲。默认值为 7。tension
:控制速度。默认值为 40。speed
:控制动画的速度。默认值为 12。bounciness
:控制弹性。默认值为 8。
将 stiffness/damping/mass 指定为参数将使 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
:为 true 时使用原生驱动。必需。
add()
static add(a: Animated, b: Animated): AnimatedAddition;
创建一个由两个相加的 Animated 值组成的新 Animated 值。
subtract()
static subtract(a: Animated, b: Animated): AnimatedSubtraction;
创建一个由第一个 Animated 值减去第二个 Animated 值组成的新 Animated 值。
divide()
static divide(a: Animated, b: Animated): AnimatedDivision;
创建一个由第一个 Animated 值除以第二个 Animated 值组成的新 Animated 值。
multiply()
static multiply(a: Animated, b: Animated): AnimatedMultiplication;
创建一个由两个相乘的 Animated 值组成的新 Animated 值。
modulo()
static modulo(a: Animated, modulus: number): AnimatedModulo;
创建一个由提供的 Animated 值(非负)取模得到的新 Animated 值。
diffClamp()
static diffClamp(a: Animated, min: number, max: number): AnimatedDiffClamp;
创建一个限制在两个值之间的新 Animated 值。它使用当前值与上一个值之间的差值,因此即使值远离边界,当值再次接近边界时也会开始变化。(即 值 = clamp(值 + 差值, 最小值, 最大值)
)。
这对于滚动事件非常有用,例如,在向上滚动时显示导航栏,在向下滚动时隐藏导航栏。
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
来解决此问题。
Config 是一个对象,可能包含以下选项:
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)}, // Optional async listener
)}
...
onPanResponderMove: Animated.event(
[
null, // raw event arg ignored
{dx: this._panX},
], // gestureState arg
{
listener: (
event: GestureResponderEvent,
gestureState: PanResponderGestureState
) => console.log(event, gestureState),
} // Optional async listener
);
Config 是一个对象,可能包含以下选项:
listener
:可选的异步监听器。useNativeDriver
:为 true 时使用原生驱动。必需。
forkEvent()
static forkEvent(event: AnimatedEvent, listener: Function): AnimatedEvent;
用于监视通过 props 传入的动画事件的高级命令式 API。它允许向现有 AnimatedEvent
添加新的 javascript 监听器。如果 animatedEvent
是 javascript 监听器,它将把两个监听器合并为一个;如果 animatedEvent
为 null/undefined,它将直接分配 javascript 监听器。在可能的情况下直接使用值。
unforkEvent()
static unforkEvent(event: AnimatedEvent, listener: Function);
start()
static start(callback?: (result: {finished: boolean}) => void);
通过在动画上调用 start() 来启动动画。start() 接受一个完成回调函数,该函数将在动画完成时被调用,或者在动画因在其完成前调用了 stop() 而结束时被调用。
参数
名称 | 类型 | 是否必需 | 描述 |
---|---|---|---|
callback | (result: {finished: boolean}) => void | 否 | 动画正常运行结束后,或动画因在其完成前调用了 stop() 而结束时调用的函数。 |
带有回调函数的 Start 示例
Animated.timing({}).start(({finished}) => {
/* completion callback */
});
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
。