Android Compose LottieAnimation顺序播放合成动画异常问题咨询
Lottie Compose 合成动画顺序播放的问题排查与解决方案
问题1:递归调用导致残影
你的第一段代码用递归调用Play(nextFile)切换动画,会导致旧的Play组件不会被Compose框架销毁,多个LottieAnimation实例叠加渲染,所以之前的动画帧会残留。这是代码逻辑问题,并非Lottie Compose不支持该功能。
问题分析
Composable的重组基于状态变化,递归调用相当于在当前组件树中新增Play节点,原有的Play仍会保留并渲染,最终多个动画层叠出现残影。
问题2:切换动画时闪烁
第二段代码的闪烁,本质是切换dir状态时,新旧动画的进度和composition切换存在间隙,再加上你在主线程执行UI阻塞操作,放大了这个间隙导致的视觉闪烁。XML实现基于View替换逻辑,切换更平滑,但Compose的重组逻辑需要更严谨的状态管理。
问题分析
- 切换
dir时,之前的动画进度会被重置,但新动画的composition可能存在短暂的状态同步延迟(即使rememberLottieComposition会缓存) - 主线程的阻塞操作会延迟重组,拉长动画切换的间隙,导致明显闪烁
问题3:阻塞操作导致首帧卡顿
第三段代码的卡顿是因为UI阻塞函数在主线程执行,和state.animate的启动同时抢占主线程资源,导致动画首帧渲染不及时,出现跳帧。animate是挂起函数,但阻塞操作不放到后台的话,会直接卡住主线程。
统一解决方案
以下是兼顾无残影、无闪烁、播放流畅的实现方案:
- 用状态变量管理当前播放的合成动画
- 用
LaunchedEffect处理播放流程,将阻塞操作放到后台线程 - 确保动画切换时进度重置,避免状态混乱
@Composable fun SequentialLottiePlayer() { // 定义要播放的动画资源列表 val animationFiles = remember { listOf(R.raw.anim1, R.raw.anim2) } val currentIndex = remember { mutableIntStateOf(0) } val currentComposition by rememberLottieComposition( LottieCompositionSpec.RawRes(animationFiles[currentIndex.value]) ) val progress by animateLottieCompositionAsState( composition = currentComposition, // 播放完成后自动重置进度,避免残留 resetOnPlay = true, // 只播放一次 iterations = 1 ) val scope = rememberCoroutineScope() LottieAnimation( composition = currentComposition, progress = { progress } ) // 播放完成后触发下一个动画 LaunchedEffect(progress) { if (progress == 1f && currentComposition != null) { // 将阻塞操作放到后台线程,避免卡主线程 scope.launch(Dispatchers.Default) { // 执行你的UI-blocking functions // ... }.join() // 等待阻塞操作完成再切换动画 // 更新索引,切换到下一个动画 currentIndex.value = (currentIndex.value + 1) % animationFiles.size } } }
关键优化点
- 用
currentIndex状态变量控制当前播放的动画,避免递归或多组件叠加 - 阻塞操作放到
Dispatchers.Default后台线程,不占用主线程资源 animateLottieCompositionAsState设置resetOnPlay = true,确保切换动画时进度重置,避免残影- 用
LaunchedEffect监听进度变化,确保播放完成后再执行后续逻辑,避免状态混乱
内容的提问来源于stack exchange,提问作者Gonki
相关产品推荐
相关产品推荐

