You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 01:10:36