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
相关产品推荐
相关产品推荐

