许多动画 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) )
有不同种类的 AnimationSpec
用于创建不同类型的动画。
使用 spring
创建基于物理的动画
spring
在起始值和结束值之间创建基于物理的动画。它接受两个参数:dampingRatio
和 stiffness
。
dampingRatio
定义弹簧的弹性程度。默认值为 Spring.DampingRatioNoBouncy
。
图 1. 设置不同的弹簧阻尼比。
stiffness
定义弹簧向结束值移动的速度。默认值为 Spring.StiffnessMedium
。
图 2. 设置不同的弹簧刚度
val value by animateFloatAsState( targetValue = 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioHighBouncy, stiffness = Spring.StiffnessMedium ) )
spring
比基于持续时间的 AnimationSpec
类型更平滑地处理中断,因为它保证了在动画过程中目标值发生变化时速度的连续性。spring
被许多动画 API 用作默认的 AnimationSpec,例如 animate*AsState
和 updateTransition
。
例如,如果我们将 spring
配置应用于以下由用户触摸驱动的动画,当在动画进行过程中中断它时,您可以看到使用 tween
的响应不如使用 spring
平滑。
图 3. 为动画设置 tween
和 spring
规范,并中断它。
使用缓动曲线在起始值和结束值之间进行动画 tween
tween
使用缓动曲线在指定的 durationMillis
内在起始值和结束值之间进行动画。tween
是“between”(之间)的缩写 - 因为它在两个值之间变化。
您还可以指定 delayMillis
来推迟动画的开始。
val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, delayMillis = 50, easing = LinearOutSlowInEasing ) )
有关更多信息,请参阅 缓动。
使用 keyframes
在特定时间点动画到特定值
keyframes
根据动画持续时间内不同时间戳上指定的快照值进行动画。在任何给定时间,动画值将在两个关键帧值之间进行插值。对于每个关键帧,可以指定缓动来确定插值曲线。
可以选择在 0 毫秒和持续时间时指定值。如果未指定这些值,则它们分别默认为动画的起始值和结束值。
val value by animateFloatAsState( targetValue = 1f, animationSpec = keyframes { durationMillis = 375 0.0f at 0 with LinearOutSlowInEasing // for 0-15 ms 0.2f at 15 with FastOutLinearInEasing // for 15-75 ms 0.4f at 75 // ms 0.4f at 225 // ms } )
使用 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 ) )
使用 infiniteRepeatable
无限重复动画
infiniteRepeatable
类似于 repeatable
,但它会无限次重复。
val value by animateFloatAsState( targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ) )
在使用 ComposeTestRule
进行的测试中,不会运行使用 infiniteRepeatable
的动画。组件将使用每个动画值的初始值进行渲染。
使用 snap
立即捕捉到结束值
snap
是一种特殊的 AnimationSpec
,它会立即将值切换到结束值。您可以指定 delayMillis
以延迟动画的开始。
val value by animateFloatAsState( targetValue = 1f, animationSpec = snap(delayMillis = 50) )
设置自定义缓动函数
基于持续时间的 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 ) ) // …… }
Compose 提供了一些内置的 Easing
函数,可以满足大多数用例。有关根据您的场景使用哪个缓动的更多信息,请参阅 速度 - Material Design。
FastOutSlowInEasing
LinearOutSlowInEasing
FastOutLinearEasing
LinearEasing
CubicBezierEasing
- 查看更多
通过转换为和从 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
本质上是一组 4 个值:红色、绿色、蓝色和 alpha,因此 Color
转换为一个包含 4 个浮点值的 AnimationVector4D
。通过这种方式,动画中使用的每种数据类型都会根据其维度转换为 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) } ) ) }
以下列表包含一些内置的 VectorConverter
。
Color.VectorConverter
Dp.VectorConverter
Offset.VectorConverter
Int.VectorConverter
Float.VectorConverter
IntSize.VectorConverter
为您推荐
- 注意:当 JavaScript 关闭时,会显示链接文本
- 基于值的动画
- 迭代代码开发 {:#iterative-code-dev }
- Compose 中的动画