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

Jetpack Compose如何实现大小可变的动态列表元素过渡动画

动态长度列表元素过渡动画实现方案(饼图场景)

核心实现思路

抛弃固定长度列表的限制,自动维护历史最大切片数量,为每个索引位置创建独立动画状态:

  • 新列表长度小于当前列表长度时,多余索引位置的动画目标值设为0,自动触发从当前占比到0的过渡
  • 新列表长度大于当前列表长度时,新增索引位置的动画初始值设为0,自动触发从0到目标占比的过渡
  • 原有存在的索引位直接从当前值动画到新的目标占比

可运行代码实现

1. 动态过渡状态生成

替换原有固定长度的updateTransitionData实现:

data class TransitionData(val fractions: List<State<Float>>)

@Composable
fun updateTransitionData(
    targetFractions: List<Float>,
    animationSpec: AnimationSpec<Float> = tween(durationMillis = 800, easing = FastOutSlowInEasing)
): TransitionData {
    // 自动维护历史出现过的最大切片数量,避免反复重建状态
    val maxSliceCount = remember { mutableIntStateOf(targetFractions.size) }
    if (targetFractions.size > maxSliceCount.intValue) {
        maxSliceCount.intValue = targetFractions.size
    }

    val transition = updateTransition(targetState = targetFractions, label = "pie-transition")
    val fractions = (0 until maxSliceCount.intValue).map { index ->
        key(index) {
            transition.animateFloat(
                label = "slice-$index-animation",
                transitionSpec = { animationSpec }
            ) { currentList ->
                // 当前索引在目标列表中存在则取目标占比,否则返回0
                currentList.getOrNull(index) ?: 0f
            }
        }
    }

    return remember(fractions) { TransitionData(fractions) }
}

2. 饼图绘制适配

绘制时过滤掉占比几乎为0的切片即可:

@Composable
fun PieChartCompose(slices: List<Float>) {
    val transitionData = updateTransitionData(slices)
    val fractions = transitionData.fractions
    // 可自定义切片颜色池
    val sliceColors = listOf(Color(0xFFE53935), Color(0xFF1E88E5), Color(0xFF43A047), Color(0xFFFFB300), Color(0xFF8E24AA))

    Canvas(modifier = Modifier.size(200.dp)) {
        var currentStartAngle = -90f
        fractions.forEachIndexed { index, fractionState ->
            val sweepAngle = fractionState.value * 360f
            // 过滤浮点误差导致的极小值切片
            if (sweepAngle > 1e-6f) {
                drawArc(
                    color = sliceColors[index % sliceColors.size],
                    startAngle = currentStartAngle,
                    sweepAngle = sweepAngle,
                    useCenter = true
                )
            }
            currentStartAngle += sweepAngle
        }
    }
}

效果验证

使用你提供的测试用例即可复现预期的过渡效果:

var slices by mutableStateOf(listOf(0.3f, 0.7f))
PieChartCompose(slices)
// 触发切片数量变更动画
slices = listOf(1f)

预期动画示例

内容的提问来源于stack exchange,提问作者Mahozad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 23:45:02