跳到主要内容

动画

Animated 库旨在让动画的构建和维护变得流畅、强大且轻松。Animated 专注于输入与输出之间的声明式关系、中间可配置的变换,以及用于控制基于时间的动画执行的 start/stop 方法。

创建动画的核心流程是创建一个 Animated.Value,将其绑定到动画组件的一个或多个样式属性上,然后通过 Animated.timing() 驱动更新。

备注

不要直接修改 animated value。你可以使用 useRef Hook 返回一个可变的 ref 对象。这个 ref 对象的 current 属性会以给定参数初始化,并在组件生命周期内持续存在。

示例

下面的示例包含一个 View,它会根据 animated value fadeAnim 实现淡入和淡出

请参阅 动画 指南,查看更多 Animated 的使用示例。

概览

Animated 可使用两种值类型:

Animated.Value 可以绑定到样式属性或其他属性,也可以进行插值。单个 Animated.Value 可以驱动任意数量的属性。

配置动画

Animated 提供三种动画类型。每种动画类型都提供一种特定的动画曲线,用于控制数值如何从初始值动画到最终值:

在大多数情况下,你会使用 timing()。默认情况下,它使用对称的 easeInOut 曲线,体现对象逐渐加速到全速,并在结束时逐渐减速至停止。

使用动画

通过在动画上调用 start() 来启动动画。start() 接收一个完成回调,该回调会在动画结束时被调用。如果动画正常结束,完成回调将收到 {finished: true}。如果动画由于在完成前调用了 stop() 而结束(例如被手势或另一个动画中断),则它将收到 {finished: false}

React TSX
Animated.timing({}).start(({finished}) => {
/* 完成回调 */
});

使用原生驱动

使用原生驱动时,我们会在动画开始前将动画的所有信息发送到原生端,这样原生代码就可以在 UI 线程上执行动画,而无需在每一帧都经过 bridge。动画开始后,即使 JS 线程被阻塞,也不会影响动画。

你可以在动画配置中指定 useNativeDriver: true 来使用原生驱动。请参阅 动画 指南了解更多。

可动画组件

只有可动画组件才能被动画化。这些独特的组件会把 animated value 绑定到属性上,并执行有针对性的原生更新,从而避免每一帧都付出 React 渲染和协调过程的成本。它们还会在卸载时处理清理,因此默认是安全的。

Animated 使用上述包装器导出了以下可动画组件:

  • Animated.Image
  • Animated.ScrollView
  • Animated.Text
  • Animated.View
  • Animated.FlatList
  • Animated.SectionList

组合动画

也可以使用组合函数以复杂方式组合动画:

通过将一个动画的 toValue 设置为另一个 Animated.Value,动画也可以串联起来。请参阅动画指南中的 跟踪动态值

默认情况下,如果一个动画停止或被中断,组中的所有其他动画也会停止。

组合 animated 值

你可以通过加法、减法、乘法、除法或取模组合两个 animated 值,创建一个新的 animated 值:

插值

interpolate() 函数允许将输入范围映射到不同的输出范围。默认情况下,它会在给定范围之外外推曲线,但你也可以让它对输出值进行截断。默认使用线性插值,但也支持缓动函数。

关于插值的更多内容,请参阅 动画 指南。

处理手势和其他事件

手势,例如拖动或滚动,以及其他事件,都可以使用 Animated.event() 直接映射到 animated 值。这通过结构化映射语法完成,因此可以从复杂的事件对象中提取值。第一层是一个数组,用于允许跨多个参数进行映射,而该数组包含嵌套对象。

例如,在处理水平滚动手势时,你可以按如下方式将 event.nativeEvent.contentOffset.x 映射到 scrollX(一个 Animated.Value):

React TSX
onScroll={Animated.event(
// scrollX = e.nativeEvent.contentOffset.x
[{nativeEvent: {
contentOffset: {
x: scrollX
}
}
}]
)}

参考

方法

当给定值是 ValueXY 而不是 Value 时,每个配置选项都可以是形如 {x: ..., y: ...} 的向量,而不是标量。

decay()

React TSX
static decay(value, config): CompositeAnimation;

根据衰减系数,将一个值从初始速度动画到零。

Config 是一个对象,可能包含以下选项:

  • velocity:初始速度。必填。
  • deceleration:衰减率。默认 0.997。
  • isInteraction:此动画是否会在 InteractionManager 上创建“交互句柄”。默认 true。
  • useNativeDriver:当为 true 时使用原生驱动。必填。

timing()

React TSX
static timing(value, config): CompositeAnimation;

沿着一个定时的缓动曲线对值进行动画。Easing 模块提供了大量预定义曲线,你也可以使用自己的函数。

Config 是一个对象,可能包含以下选项:

  • duration:动画时长(毫秒)。默认 500。
  • easing:用于定义曲线的缓动函数。默认是 Easing.inOut(Easing.ease)
  • delay:在延迟后开始动画(毫秒)。默认 0。
  • isInteraction:此动画是否会在 InteractionManager 上创建“交互句柄”。默认 true。
  • useNativeDriver:当为 true 时使用原生驱动。必填。

spring()

React TSX
static spring(value, config): CompositeAnimation;

根据基于 阻尼谐振动 的解析弹簧模型对值进行动画。跟踪速度状态,以在 toValue 更新时创建流畅的运动,并且可以彼此串联。

Config 是一个对象,可能包含以下选项。

请注意,你只能定义 bounciness/speed、tension/friction 或 stiffness/damping/mass 其中之一,不能定义多个:

friction/tension 或 bounciness/speed 选项与 Facebook PopReboundOrigami 中的弹簧模型一致。

  • 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()

React TSX
static add(a: Animated, b: Animated): AnimatedAddition;

创建一个新的 Animated 值,由两个相加的 Animated 值组成。


subtract()

React TSX
static subtract(a: Animated, b: Animated): AnimatedSubtraction;

创建一个新的 Animated 值,由第一个 Animated 值减去第二个 Animated 值组成。


divide()

React TSX
static divide(a: Animated, b: Animated): AnimatedDivision;

创建一个新的 Animated 值,由第一个 Animated 值除以第二个 Animated 值组成。


multiply()

React TSX
static multiply(a: Animated, b: Animated): AnimatedMultiplication;

创建一个新的 Animated 值,由两个相乘的 Animated 值组成。


modulo()

React TSX
static modulo(a: Animated, modulus: number): AnimatedModulo;

创建一个新的 Animated 值,它是所提供 Animated 值的(非负)取模结果


diffClamp()

React TSX
static diffClamp(a: Animated, min: number, max: number): AnimatedDiffClamp;

创建一个受限于两个值之间的新 Animated 值。它使用上一个值之间的差值,因此即使值远离边界,当值再次开始接近时,它也会开始变化。(value = clamp(value + diff, min, max))。

这在滚动事件中很有用,例如,向上滚动时显示导航栏,向下滚动时隐藏它。


delay()

React TSX
static delay(time: number): CompositeAnimation;

在给定延迟后启动动画。


sequence()

React TSX
static sequence(animations: CompositeAnimation[]): CompositeAnimation;

按顺序启动一组动画,等待每个动画完成后再启动下一个。如果当前正在运行的动画被停止,则不会启动后续动画。


parallel()

React TSX
static parallel(
animations: CompositeAnimation[],
config?: ParallelConfig
): CompositeAnimation;

同时启动一组动画。默认情况下,如果其中一个动画被停止,它们都会被停止。你可以通过 stopTogether 标志覆盖这一行为。


stagger()

React TSX
static stagger(
time: number,
animations: CompositeAnimation[]
): CompositeAnimation;

动画数组可以并行运行(重叠),但会按顺序以递增的延迟启动。非常适合制作尾随效果。


loop()

React TSX
static loop(
animation: CompositeAnimation[],
config?: LoopAnimationConfig
): CompositeAnimation;

连续循环给定动画,使其每次到达结尾时都会重置并从头开始。若子动画设置了 useNativeDriver: true,则循环不会阻塞 JS 线程。此外,循环会阻止基于 VirtualizedList 的组件在动画运行时渲染更多行。你可以在子动画配置中传入 isInteraction: false 来解决此问题。

Config 是一个对象,可能包含以下选项:

  • iterations:动画应循环的次数。默认 -1(无限循环)。

event()

React TSX
static event(
argMapping: Mapping[],
config?: EventConfig
): (...args: any[]) => void;

接收一个映射数组,并相应地从每个参数中提取值,然后对映射后的输出调用 setValue。例如:

React TSX
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),
} // 可选的异步监听器
);

Config 是一个对象,可能包含以下选项:

  • listener:可选的异步监听器。
  • useNativeDriver:当为 true 时使用原生驱动。必填。

forkEvent()

React JSX
static forkEvent(event: AnimatedEvent, listener: Function): AnimatedEvent;

用于监听通过 props 传入的 animated 事件的高级命令式 API。它允许向现有的 AnimatedEvent 添加一个新的 javascript 监听器。如果 animatedEvent 是一个 javascript 监听器,它会将这两个监听器合并为一个;如果 animatedEvent 为 null/undefined,则会直接分配该 javascript 监听器。尽可能直接使用值。


unforkEvent()

React JSX
static unforkEvent(event: AnimatedEvent, listener: Function);

start()

React TSX
static start(callback?: (result: {finished: boolean}) => void);

通过在动画上调用 start() 来启动动画。start() 接收一个完成回调,该回调会在动画正常结束时,或由于在完成前调用了 stop() 而结束时被调用。

参数:

名称类型是否必填描述
callback(result: {finished: boolean}) => void动画正常完成后,或由于在完成前调用了 stop() 而结束时,将被调用的函数

带回调的 start 示例:

React TSX
Animated.timing({}).start(({finished}) => {
/* 完成回调 */
});

stop()

React TSX
static stop();

停止任何正在运行的动画。


reset()

React TSX
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

用于将动画值以命令式方式附加到视图上的事件。若可能,优先使用带有 useNativeDriver: trueAnimated.event