先上效果预览:

前言:
Compose UI系统是通过状态(state)去控制并实现的动画功能,其类似于View系统的属性动画,通过修改变量属性来实现动画的功能。但是对于更早的视图动画,比如这里想要实现的帧动画,则没有现成的动画Api来实现(虽然可以通过判断动画的临界值来实现该动画功能,但是会造成不必要的视图重组)。
所以本文将结合Kotlin flow,通过发送定时消息来实现一个帧动画的功能。该功能实现起来并不难,只是为了避免重复造轮子。由于个人能力有限,欢迎大家给出自己的建议、指正和更好的实现方式。
实现:
1.定义一个无限并且周期性发送一条消息的流,代码如下所示:
/**
* 无限并且周期性发送一条消息的流
* @param periodInTimeMillis 周期时长
* 第一个发送的值为1
*/
fun infiniteWithPeriod(periodInTimeMillis: Long) = flow {
var counter = 0 // 控制展示不同的图片
while (true) {
emit(++counter)
delay(periodInTimeMillis)
}
}
2.定义一个方法,根据counter和要显示图片数量的余数返回要显示的图片资源id,代码如下所示:
/**
* 根据余数来判断要显示的图片
* @param remainder 余数
*/
fun getVoiceResIntByRemainder(remainder: Int) = when (remainder) {
1 -> R.mipmap.voice_recognize_1 // 初始图片
2 -> R.mipmap.voice_recognize_2
else -> R.mipmap.voice_recognize_3
}
3.实现Composable视图方法,代码如下所示:
@SuppressLint("RememberReturnType")
@Composable
fun RecordingView() {
var resIntForVoice by remember {
mutableStateOf(R.mipmap.voice_recognize_1)
}
LaunchedEffect(Unit) {
infiniteWithPeriod(300).collect {
resIntForVoice = getVoiceResIntByRemainder(it % 3) // 因为只有3张图片,所有这里求3的余数,当余数为0时,加载最后一张图片。循环类型类似于restart,每次都是重新开始。Value is on 012 by 012 etc.
}
}
Box(
modifier = Modifier
.size(100.dp)
.clip(RoundedCornerShape(5.dp))
.background(color = Black900), contentAlignment = Alignment.Center
) {
Image(painter = painterResource(id = resIntForVoice), contentDescription = "正在录音提示")
}
}
4.到这里就完成了。完整Demo AnimationDrawable的github地址
本文介绍如何使用Compose UI结合Kotlinflow实现帧动画。通过无限周期性发送消息的流更新视图状态,达到帧动画效果。
654

被折叠的 条评论
为什么被折叠?



