How can I transition elements of a list to the new list (possibly different size) with animation?
I have a pie chart and when its slices (fractions) change, I want to animate the previous fractions to the new fractions. The thing is, number of slices can be different each time.
If number of new slices is less than the current ones, the current extra slices should animate from their current fraction to 0
.
If number of new slices is greater than the current ones, new extra slices should animate from 0
to their fractions.
@Composable fun PieChartCompose(slices: List<Float>) {
val transitionData = updateTransitionData(slices)
val fractions = transitionData.fractions
// Draw the pie with Canvas using the fractions
}
I have currently implemented this with a list of constant size (10, so slices cannot be more than 10)
(note that the initial animation for chart appearance can be different from subsequent animations):
data class TransitionData(val slices: List<State<Float>>)
enum class ChartState { INITIALIZED, CHANGED }
@Composable fun updateTransitionData(
targetFractions: List<Float>
): TransitionData {
val mutableState = remember { MutableTransitionState(ChartState.INITIALIZED) }
mutableState.targetState = ChartState.CHANGED
val transition = updateTransition(mutableState, label = "main-animation")
val fractions = listOf(
transition.animateFloat(label = "fraction-0-animation") {
if (it == ChartState.INITIALIZED) 0f
else targetSlices.getOrNull(0)?.fraction ?: 0f
},
// ...
transition.animateFloat(label = "fraction-10-animation") {
if (it == ChartState.INITIALIZED) 0f
else targetSlices.getOrNull(10)?.fraction ?: 0f
}
)
return remember(transition) { TransitionData(fractions) }
}
Below is an example chart that initially has two slices and then animates to one slice
(the first slice animates to the single new fraction and the second slice animates to 0
—
they are a little inconsistent probably because of interpolations and animation specs):
var slices by mutableStateOf(listOf(0.3f, 0.7f))
PieChartCompose(slices)
slices = listOf(1f)