状态转移型动画 AnimateXxxAsState()

传统View系统的属性动画

在了解Compose的动画之前,我们先来看看传统View系统中的属性动画是什么。

一个属性动画的简单示例:

java 复制代码
// 获取按钮组件
View view = findViewById(R.id.my_button);

// 创建动画,让按钮从0移动到300像素的位置(X轴)
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 0f, 300f);
animator.setDuration(1000); // 动画持续1秒

// 启动动画
animator.start();

在这个示例中,它可以让一个按钮:从左边移动到右边。

以上只是基本的使用,我们还可以添加:

  • 动画监听器(AnimatorListener) 来响应动画的不同阶段,比如在动画开始/结束/取消/重复 阶段,做一些操作。

  • 插值器(Interpolator) :控制动画的变化速度,它决定了动画在不同时间点的完成程度,我们可以让动画先加速后减速、先加速后加速、匀速,或者以弹跳曲线来变化速度。

  • 估值器(TypeEvaluator) :计算属性在起始值和结束值之间的实际数值,就是此次动画的变化量。

说了这么多,好像懂了?

不懂没关系,总结一下,属性动画过程:在指定的时间内,以帧为单位平滑地修改对象的属性值,从而实现流畅的动画效果。

如果用一张图来形象地这个过程就是:

而Compose是声明式UI框架,我们是描述各状态下的界面外观,所以不是去直接操作UI元素。

那该怎么办才能实现动画呢?你可能已经想到了,答案就在上一行,不断修改界面的描述状态就可以了。

是不是觉得很难,别担心,Compose官方已经为我们实现了一整套的动画API。

AnimateXxxAsState()

我们先来自己实现一个变化效果,点击绿色矩形,矩形会变大:

kotlin 复制代码
var size by remember { mutableStateOf(48.dp) }
Box(Modifier
    .size(size)
    .background(Color.Green)
    .clickable {
        size = 96.dp
    })

很明显,这种突变效果并不是真正意义上的动画。所以我们使用Compose为我们提供的animateDpAsState()函数来改造它:

kotlin 复制代码
var size by animateDpAsState(48.dp)
Box(Modifier
    .size(size)
    .background(Color.Green)
    .clickable {
        size = 96.dp
    })

animateDpAsState()函数具有重组时防止重复初始化创建一个可观察的状态对象的功能,所以只需一个函数就可以完成之前两个函数的工作。

可是修改后,发现报错了:

perl 复制代码
Type 'State<Dp>' has no method 'setValue(Nothing?, KProperty<*>, Dp)' and thus it cannot serve as a delegate for var (read-write property)

不对啊,你刚刚不是说animateDpAsState()函数可以替换掉前面的两个函数吗?怎么替换后,还错了。

这是因为之前的mutableStateOf()函数返回的是一个MutableState<Dp>类型的对象,可以对它的value属性进行读写;而animateDpAsState()函数返回的是一个State<Dp>类型的对象,它的value属性是只读的,所以我们不能进行修改。

那不能修改,动画还怎么进行下去啊,你不是就是要去不断地修改描述状态,才可以实现动画吗?

别急只是我们开发者不能修改,具体的修改过程由框架内部去完成。我们只需使用下面这种方式,就能完成动画了:

kotlin 复制代码
var big by remember { mutableStateOf(false) }
val size by animateDpAsState(targetValue = if (big) 96.dp else 48.dp)
Box(Modifier
    .size(size)
    .background(Color.Green)
    .clickable {
        big = !big
    })

这种方式来写的动画,代码非常简洁,我们只需声明目标状态应该是什么,不必关心状态的过渡细节。

注意: AnimateXxxAsState()是一个系列函数,其中还有animateIntAsState、animateOffsetAsState等函数,可以用于不同类型的动画过渡。

animateXxxAsState()的工作流程

  1. 创建AnimationState内部对象,并设置初始值和目标值。
kotlin 复制代码
val size by animateDpAsState(targetValue = if (big) 96.dp else 48.dp)
  1. 检测到targetValue目标值发生改变时,就开启一个动画。
kotlin 复制代码
// big值改变
var big by remember { mutableStateOf(false) }
  1. 动画运行期间,会在每一帧计算值,更新到AnimationState内部对象的value上,并且这个value值的更新会触发重组,导致使用到这个值的组件重组。
  2. 在达到目标值后,动画结束。
相关推荐
Libraeking18 小时前
破壁行动:在旧项目中丝滑嵌入 Compose(混合开发实战)
android·经验分享·android jetpack
Libraeking2 天前
导航之弦:Compose Navigation 的深度解耦与类型安全
经验分享·android jetpack
撩得Android一次心动2 天前
Android LiveData 全面解析:使用Java构建响应式UI【源码篇】
android·java·android jetpack·livedata
符哥20084 天前
关于用Android Compose开发成不成熟的分析
android·android jetpack
蹦哒7 天前
Jetpack Compose Surface 完全指南
android jetpack
我命由我123457 天前
Android 开发 Room 数据库升级问题:A migration from 6 to 7 was required but not found.
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123459 天前
Android 控件 - 最简单的 Notification、Application Context 应用于 Notification
android·java·开发语言·junit·android studio·android jetpack·android-studio
工程师老罗10 天前
我用Ai学Android Jetpack Compose之Text
android·android jetpack
tangweiguo0305198710 天前
Android Jetpack Compose 面试题大全(2025最新整理)
android·android jetpack
安卓开发者10 天前
Android Jetpack Compose:现代声明式UI开发指南
android·ui·android jetpack