Android 使用Compose实现类似View系统的帧动画功能

先上效果预览:

Android 使用Compose实现类似View系统的帧动画功能_第1张图片

 前言:

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地址

你可能感兴趣的:(#,Animation,android,Compose,Compose帧动画)