许多动画 API 通常接受用于自定义其行为的参数。
使用 AnimationSpec
参数自定义动画
大多数动画 API 允许开发者通过可选的 AnimationSpec
参数自定义动画规格。
val alpha: Float by animateFloatAsState( targetValue = if (enabled) 1f else 0.5f, // Configure the animation duration and easing. animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing), label = "alpha" )
有不同类型的 AnimationSpec
用于创建不同类型的动画。
使用 spring
创建基于物理的动画
spring
在开始值和结束值之间创建基于物理的动画。它接受 2 个参数:dampingRatio
和 stiffness
。
dampingRatio
定义弹簧的弹性。默认值为 Spring.DampingRatioNoBouncy
。
stiffness
定义弹簧移动到结束值的速度。默认值为 Spring.StiffnessMedium
。
val value by animateFloatAsState( targetValue = 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioHighBouncy, stiffness = Spring.StiffnessMedium ), label = "spring spec" )
spring
比基于持续时间的 AnimationSpec
类型更能平滑地处理中断,因为它在动画进行中目标值更改时保证了速度的连续性。spring
作为许多动画 API(例如 animate*AsState
和 updateTransition
)的默认 AnimationSpec 使用。
例如,如果我们将 spring
配置应用于以下由用户触摸驱动的动画,当动画进行中被中断时,您可以看到使用 tween
的响应不如使用 spring
流畅。
tween
与 spring
规格,并中断它。使用 tween
在开始值和结束值之间以缓动曲线进行动画
tween
使用缓动曲线在指定 durationMillis
期间在开始值和结束值之间进行动画。tween
是单词 "between" 的缩写 - 因为它在两个值“之间”移动。
您还可以指定 delayMillis
来延迟动画的开始。
val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, delayMillis = 50, easing = LinearOutSlowInEasing ), label = "tween delay" )
有关更多信息,请参阅缓动。
使用 keyframes
在特定时间点动画到特定值
keyframes
根据动画持续时间中不同时间戳指定的快照值进行动画。在任何给定时间,动画值都将在两个关键帧值之间进行插值。对于每个关键帧,可以指定缓动以确定插值曲线。
在 0 毫秒和持续时间时指定值是可选的。如果您不指定这些值,它们将分别默认为动画的开始值和结束值。
val value by animateFloatAsState( targetValue = 1f, animationSpec = keyframes { durationMillis = 375 0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms 0.2f at 15 using FastOutLinearInEasing // for 15-75 ms 0.4f at 75 // ms 0.4f at 225 // ms }, label = "keyframe" )
使用 keyframesWithSplines
平滑地在关键帧之间进行动画
要创建在值之间平滑过渡的动画,您可以使用 keyframesWithSplines
而不是 keyframes
动画规格。
val offset by animateOffsetAsState( targetValue = Offset(300f, 300f), animationSpec = keyframesWithSpline { durationMillis = 6000 Offset(0f, 0f) at 0 Offset(150f, 200f) atFraction 0.5f Offset(0f, 100f) atFraction 0.7f } )
基于样条曲线的关键帧对于屏幕上项目的 2D 移动特别有用。
以下视频展示了在给定相同的一组圆应该遵循的 x, y 坐标的情况下,keyframes
和 keyframesWithSpline
之间的区别。
关键帧
|
带样条曲线的关键帧
|
---|---|
如您所见,基于样条曲线的关键帧提供了更平滑的点间过渡,因为它们使用贝塞尔曲线在项目之间平滑动画。此规格对于预设动画很有用。但是,如果您正在处理用户驱动的点,最好使用弹簧在点之间实现类似的平滑度,因为它们是可中断的。
使用 repeatable
重复动画
repeatable
反复运行基于持续时间的动画(例如 tween
或 keyframes
),直到达到指定的迭代次数。您可以传入 repeatMode
参数来指定动画是应该从头开始重复 (RepeatMode.Restart
) 还是从尾部开始重复 (RepeatMode.Reverse
)。
val value by animateFloatAsState( targetValue = 1f, animationSpec = repeatable( iterations = 3, animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "repeatable spec" )
使用 infiniteRepeatable
无限重复动画
infiniteRepeatable
类似于 repeatable
,但它无限次重复。
val value by animateFloatAsState( targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "infinite repeatable" )
在使用 ComposeTestRule
的测试中,使用 infiniteRepeatable
的动画不会运行。组件将使用每个动画值的初始值进行渲染。
使用 snap
立即捕捉到结束值
snap
是一种特殊的 AnimationSpec
,它立即将值切换到结束值。您可以指定 delayMillis
以延迟动画的开始。
val value by animateFloatAsState( targetValue = 1f, animationSpec = snap(delayMillis = 50), label = "snap spec" )
设置自定义缓动函数
基于持续时间的 AnimationSpec
操作(例如 tween
或 keyframes
)使用 Easing
来调整动画的分数。这允许动画值加速和减速,而不是以恒定速率移动。分数是一个介于 0(开始)和 1.0(结束)之间的值,表示动画中的当前点。
缓动实际上是一个函数,它接受 0 到 1.0 之间的分数,并返回一个浮点数。返回值可以超出边界以表示过冲或欠冲。可以按照以下代码创建自定义缓动。
val CustomEasing = Easing { fraction -> fraction * fraction } @Composable fun EasingUsage() { val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, easing = CustomEasing ), label = "custom easing" ) // …… }
Compose 提供了几个内置的 Easing
函数,涵盖了大多数用例。有关根据您的场景使用哪种缓动的更多信息,请参阅速度 - Material Design。
FastOutSlowInEasing
LinearOutSlowInEasing
FastOutLinearEasing
LinearEasing
CubicBezierEasing
- 查看更多
通过转换为 AnimationVector
和从 AnimationVector
转换来动画自定义数据类型
大多数 Compose 动画 API 默认支持 Float
、Color
、Dp
和其他基本数据类型作为动画值,但有时您需要动画其他数据类型,包括您的自定义数据类型。在动画期间,任何动画值都表示为 AnimationVector
。该值通过相应的 TwoWayConverter
转换为 AnimationVector
,反之亦然,以便核心动画系统能够统一处理它们。例如,Int
表示为 AnimationVector1D
,它包含一个浮点值。Int
的 TwoWayConverter
如下所示
val IntToVector: TwoWayConverter<Int, AnimationVector1D> = TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })
Color
本质上是红、绿、蓝和 alpha 的 4 个值的集合,因此 Color
被转换为 AnimationVector4D
,它包含 4 个浮点值。通过这种方式,动画中使用的每种数据类型都根据其维度转换为 AnimationVector1D
、AnimationVector2D
、AnimationVector3D
或 AnimationVector4D
。这允许对象的不同组件独立动画,每个组件都有自己的速度跟踪。可以使用 Color.VectorConverter
或 Dp.VectorConverter
等转换器访问基本数据类型的内置转换器。
当您想为新的数据类型添加动画值支持时,您可以创建自己的 TwoWayConverter
并将其提供给 API。例如,您可以使用 animateValueAsState
像这样动画您的自定义数据类型
data class MySize(val width: Dp, val height: Dp) @Composable fun MyAnimation(targetSize: MySize) { val animSize: MySize by animateValueAsState( targetSize, TwoWayConverter( convertToVector = { size: MySize -> // Extract a float value from each of the `Dp` fields. AnimationVector2D(size.width.value, size.height.value) }, convertFromVector = { vector: AnimationVector2D -> MySize(vector.v1.dp, vector.v2.dp) } ), label = "size" ) }
以下列表包含一些内置的 VectorConverter
Color.VectorConverter
Dp.VectorConverter
Offset.VectorConverter
Int.VectorConverter
Float.VectorConverter
IntSize.VectorConverter
为您推荐
- 注意:当 JavaScript 关闭时显示链接文本
- 基于值的动画
- 迭代式代码开发 {:#iterative-code-dev }
- Compose 中的动画