设置自定义缓动函数

2025-12-07 14:56:44

很多动画 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"

)AnimationSnippets.kt

开发者可以使用不同类型的 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"

)AnimationSnippets.kt

相比基于时长的 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"

)AnimationSnippets.kt

如需了解详情,请参阅 Easing。

使用 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"

)AnimationSnippets.kt

使用 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

}

)AnimationSnippets.kt

基于样条曲线的关键帧对于屏幕上项的 2D 移动特别有用。

以下视频展示了在给定一组相同的 x、y 坐标(圆应遵循的坐标)的情况下,keyframes 和 keyframesWithSpline 之间的差异。

keyframes

keyframesWithSplines

如图所示,基于样条的关键帧可在点之间实现更平滑的过渡,因为它们使用贝塞尔曲线在项之间平滑地实现动画效果。此规范适用于预设动画。不过,如果您使用的是用户驱动的点,最好使用弹簧在点之间实现类似的平滑度,因为弹簧是可以中断的。

使用 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"

)AnimationSnippets.kt

使用 infiniteRepeatable 无限重复播放动画

infiniteRepeatable 与 repeatable 类似,但它会重复无限次的迭代。

val value by animateFloatAsState(

targetValue = 1f,

animationSpec = infiniteRepeatable(

animation = tween(durationMillis = 300),

repeatMode = RepeatMode.Reverse

),

label = "infinite repeatable"

)AnimationSnippets.kt

在使用 ComposeTestRule 的测试中,使用 infiniteRepeatable 的动画不会运行。系统将使用每个动画值的初始值来呈现组件。

使用 snap 立即贴靠到结束值

snap 是特殊的 AnimationSpec,它会立即将值切换到结束值。您可以指定 delayMillis 来延迟动画播放的开始时间。

val value by animateFloatAsState(

targetValue = 1f,

animationSpec = snap(delayMillis = 50),

label = "snap spec"

)AnimationSnippets.kt

注意: 在 View 系统中,对于基于时长的动画,您需要使用 ObjectAnimator;对于基于物理特性的动画,则需要使用 SpringAnimation。同时使用这两个不同的动画 API 并不容易。Compose 中的 AnimationSpec 让我们能够以统一的方式处理这些动画。

设置自定义缓动函数

基于时长的 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"

)

// ……

}AnimationSnippets.kt

Compose 提供多种内置 Easing 函数,可满足大多数用例的需要。如需详细了解根据您的情况应使用哪种 Easing,请参阅速度 - Material Design。

FastOutSlowInEasing

LinearOutSlowInEasing

FastOutLinearEasing

LinearEasing

CubicBezierEasing

查看更多

注意:Easing 对象的运行方式与平台中 Interpolator 类的实例相同。不过,它采用的不是 getInterpolation() 方法,而是 transform() 方法。

通过转换为 AnimationVector 和从 AnimationVector 转换来为自定义数据类型添加动画效果

大多数 Compose 动画 API 默认支持将 Float、Color、Dp 以及其他基本数据类型作为动画值,但有时您需要为其他数据类型(包括您的自定义类型)添加动画效果。在动画播放期间,任何动画值都表示为 AnimationVector。使用相应的 TwoWayConverter 即可将值转换为 AnimationVector,反之亦然,这样一来,核心动画系统就可以统一对其进行处理。例如,Int 表示为包含单个浮点值的 AnimationVector1D。用于 Int 的 TwoWayConverter 如下所示:

val IntToVector: TwoWayConverter =

TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })AnimationSnippets.kt

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"

)

}AnimationSnippets.kt

以下列表包含一些内置 VectorConverter:

Color.VectorConverter

Dp.VectorConverter

Offset.VectorConverter

Int.VectorConverter

Float.VectorConverter

IntSize.VectorConverter

为您推荐

注意:当 JavaScript 处于关闭状态时,系统会显示链接文字

基于价值的动画

迭代代码开发 {:#iterative-code-dev }

Compose 中的动画

Copyright © 2022 角动游戏活动平台 - 全网网游动态实时追踪 All Rights Reserved.