很多动画 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
。
图 1. 设置不同的弹簧阻尼比。
stiffness
定义弹簧应向结束值移动的速度。默认值为 Spring.StiffnessMedium
。
图 2. 设置不同的弹簧刚度
val value by animateFloatAsState( targetValue = 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioHighBouncy, stiffness = Spring.StiffnessMedium ), label = "spring spec" )
相比基于时长的 AnimationSpec
类型,spring
可以更流畅地处理中断,因为它可以在目标值在动画中变化时保证速度的连续性。spring
用作很多动画 API(如 animate*AsState
和 updateTransition
)的默认 AnimationSpec。
例如,如果我们将 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 ), label = "tween delay" )
如需了解详情,请参阅缓动。
使用 keyframes
在特定时间点以动画方式呈现特定值
keyframes
会根据在动画时长内的不同时间戳中指定的快照值添加动画效果。在任何给定时间,动画值都将插值到两个关键帧值之间。对于其中每个关键帧,您都可以指定 Easing 来确定插值曲线。
您可以选择在 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" )
使用 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(结束值)之间的值,表示动画中的当前点。
Easing 实际上是一个函数,它取一个介于 0 和 1.0 之间的小数值并返回一个浮点数。返回的值可能位于边界之外,表示过冲或下冲。您可以使用如下所示的代码创建一个自定义 Easing。
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
函数,可满足大多数用例的需要。如需详细了解根据您的情况应使用哪种 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
实际上是 red、green、blue 和 alpha 这 4 个值的集合,因此,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) } ), label = "size" ) }
以下列表包含一些内置 VectorConverter
:
Color.VectorConverter
Dp.VectorConverter
Offset.VectorConverter
Int.VectorConverter
Float.VectorConverter
IntSize.VectorConverter
为您推荐
- 注意:当 JavaScript 处于关闭状态时,系统会显示链接文字
- 基于价值的动画
- 迭代代码开发 {:#iterative-code-dev }
- Compose 中的动画