使用Jetpack Compose更新Lottie动画出现闪烁问题求助
问题分析与解决方案
你的闪烁问题主要来自两个核心问题:状态管理不当导致的不必要重组,以及动画播放逻辑没有控制单次播放、切换时两个动画重叠渲染。下面是具体的修正方案:
1. 修复状态管理问题
你当前使用的selectedIndex和previousSelectedIndex需要用Compose的mutableStateOf包裹,确保状态变化能正确触发重组,同时避免状态丢失。在父Composable中修改:
val selectedIndex = remember { mutableStateOf(0) } val previousSelectedIndex = remember { mutableStateOf(-1) } val shouldPlayCloseAnim = remember { mutableStateOf(false) }
2. 控制Lottie动画单次播放
你的NavBarAnimation默认会循环播放动画,这会导致切换时动画重复触发,需要修改为仅播放一次,并添加完成回调:
@Composable fun NavBarAnimation( modifier: Modifier = Modifier, animation: Int, animationSpeed: Float = 1f, animationScale: Float = 1f, playOnce: Boolean = false, onAnimFinished: () -> Unit = {} ) { val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(animation)) val isPlaying = remember { mutableStateOf(true) } val progress by animateLottieCompositionAsState( composition = composition, speed = animationSpeed, isPlaying = isPlaying.value, restartOnPlay = true, onFinished = { if (playOnce) { isPlaying.value = false onAnimFinished() } } ) LottieAnimation( modifier = modifier .fillMaxSize() .scale(animationScale), composition = composition, progress = { progress } ) }
3. 优化BottomNavigationItem的动画切换逻辑
修改点击事件和图标渲染逻辑,确保关闭动画播放完成后再清理状态,避免两个动画同时显示:
BottomNavigationItem( selected = selectedIndex.value == index, icon = { Column( modifier = Modifier .fillMaxHeight() .padding(top = LVAppDesignKitTheme.dimens.dimens14), horizontalAlignment = Alignment.CenterHorizontally, ) { // ... 其他UI元素 Box { val isSelected = selectedIndex.value == index val isPrevSelected = previousSelectedIndex.value == index // 选中项播放开启动画(单次) if (isSelected) { NavBarAnimation( animation = navigationItem.openAnimation, playOnce = true ) } // 上一项播放关闭动画,完成后重置状态 else if (isPrevSelected && shouldPlayCloseAnim.value) { NavBarAnimation( animation = navigationItem.closeAnimation, playOnce = true, onAnimFinished = { shouldPlayCloseAnim.value = false previousSelectedIndex.value = -1 } ) } // 未选中且无动画时显示默认状态 else { // 这里放你的默认静态图标 } } } }, onClick = { if (selectedIndex.value != index) { previousSelectedIndex.value = selectedIndex.value selectedIndex.value = index shouldPlayCloseAnim.value = true } }, interactionSource = interactionSource )
关键优化点说明
- 用
mutableStateOf管理状态,确保状态变化仅触发必要的重组,避免无效渲染。 - 关闭动画播放完成后才重置
previousSelectedIndex,彻底避免两个动画同时渲染导致的闪烁。 - 强制动画单次播放,防止循环播放带来的视觉干扰。
内容的提问来源于stack exchange,提问作者Boysteuf
相关产品推荐
相关产品推荐

