Jetpack Compose中如何监听Lottie动画的结束事件?
如何在Jetpack Compose中监听Lottie动画结束?
我正在Jetpack Compose中使用Lottie动画,当前的实现代码如下:
val logoAnimationComposition by rememberLottieComposition( spec = LottieCompositionSpec.RawRes( resId = R.raw.twitter_logo_motion ) ) val logoAnimationProgress by animateLottieCompositionAsState( composition = logoAnimationComposition, isPlaying = true ) LottieAnimation( modifier = Modifier.size( size = logoSize ), composition = logoAnimationComposition, progress = logoAnimationProgress )
我需要知道这个动画什么时候结束。虽然可以通过UI设计师提供的动画时长来处理,但这不是理想的方案,而且官方文档也没提到对应的解决方法。请问我该怎么实现监听Lottie动画结束的功能?
解决方案1:利用原生onFinished回调(推荐)
最省心可靠的方式是直接使用animateLottieCompositionAsState提供的onFinished参数,这是Lottie为Compose场景专门设计的结束回调,完全不需要依赖外部时长:
val logoAnimationComposition by rememberLottieComposition( spec = LottieCompositionSpec.RawRes(R.raw.twitter_logo_motion) ) val isPlaying = remember { mutableStateOf(true) } val logoAnimationProgress by animateLottieCompositionAsState( composition = logoAnimationComposition, isPlaying = isPlaying.value, // 动画自然结束时自动触发此回调 onFinished = { // 在这里编写你的结束逻辑,比如页面跳转、显示提示等 println("Lottie动画播放完毕啦!") // 如果不想重复播放,可将播放状态设为false isPlaying.value = false } ) LottieAnimation( modifier = Modifier.size(logoSize), composition = logoAnimationComposition, progress = logoAnimationProgress )
⚠️ 注意:如果你的动画设置了repeatCount = LottieConstants.IterateForever(无限循环),这个回调不会触发——毕竟动画永远不会自然结束。这种情况下可以手动设置循环次数,比如repeatCount = 1让动画只播放一次。
解决方案2:监听进度值达到100%
如果因为特殊场景没法用onFinished,也可以通过监听进度值是否达到1.0f(代表动画播放到最后一帧)来判断结束:
val logoAnimationComposition by rememberLottieComposition( spec = LottieCompositionSpec.RawRes(R.raw.twitter_logo_motion) ) val isPlaying = remember { mutableStateOf(true) } val logoAnimationProgress by animateLottieCompositionAsState( composition = logoAnimationComposition, isPlaying = isPlaying.value ) // 用LaunchedEffect监听进度变化 LaunchedEffect(logoAnimationProgress, isPlaying.value) { // 只有当动画处于播放状态,且进度达到1.0f时才触发结束逻辑 if (logoAnimationProgress >= 1f && isPlaying.value) { println("动画播放完成!") isPlaying.value = false } } LottieAnimation( modifier = Modifier.size(logoSize), composition = logoAnimationComposition, progress = logoAnimationProgress )
这种方式需要注意:如果动画有反向播放、手动调整进度的情况,可能会误触发,所以一定要配合isPlaying状态一起判断。
不推荐的方案:依赖动画时长
你提到的用设计师给的时长确实不太理想,不过如果一定要用,也可以从Lottie的Composition中直接读取时长(避免手动输入出错):
val logoAnimationComposition by rememberLottieComposition( spec = LottieCompositionSpec.RawRes(R.raw.twitter_logo_motion) ) val isPlaying = remember { mutableStateOf(true) } val logoAnimationProgress by animateLottieCompositionAsState( composition = logoAnimationComposition, isPlaying = isPlaying.value ) LaunchedEffect(logoAnimationComposition) { logoAnimationComposition?.let { comp -> // 从动画文件中获取总时长(毫秒) val totalMs = comp.duration.toLong() delay(totalMs) if (isPlaying.value) { println("动画结束") isPlaying.value = false } } } LottieAnimation( modifier = Modifier.size(logoSize), composition = logoAnimationComposition, progress = logoAnimationProgress )
但这种方式有明显缺陷:如果动画中途被暂停、取消,延迟的协程还是会执行,容易出现逻辑错误,所以除非万不得已,不建议使用。
内容的提问来源于stack exchange,提问作者MohammadBaqer




