You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动