androidandroid-jetpack-composeandroid-animationjetpack-compose-animation

Jetpack Compose - Animate recomposition on state change


I am having trouble animating a composable on a state change.

I have a composable that receives an object of type Interval (custom class) and List. These are dynamically generated throughout the activity usage, with a ViewModel.

How can I animate the ExerciseView recomposition when the state of interval and answerOptions change, having the old version of the composable sliding out, and the new version sliding in?

@Composable
fun ExerciseView(interval: State<Interval>, answerOptions: State<List<Int>>, audioGenerator: AudioGenerator){
    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {

        //Composable
        IntervalPlayer(
            interval.value,
            audioGenerator
        )

        //Composable
        OptionButtonList(answerOptions.value, interval.value.semitones - 1)
    }
}

I have been looking at the animation documentation, but I cannot find any information regarding custom objects state change, only for properties like visibility, color, position and scale.

Thank you in advance!


Solution

  • You can do this by wrapping your content in AnimatedContent.

    enter image description here

    data class CustomClass(val number: Int)
    
    @Composable
    fun ExerciseScreen() {
        val customState = remember {
            mutableStateOf(CustomClass(1))
        }
        ExerciseView(customState) { customState.value = CustomClass(Random.nextInt()) }
    }
    
    @Composable
    fun ExerciseView(
        customState: State<CustomClass>,
        onClick: () -> Unit,
    ) {
        AnimatedContent(
            targetState = customState.value,
            transitionSpec = {
                slideInHorizontally(
                    initialOffsetX = { fullWidth -> fullWidth },
                ) togetherWith slideOutHorizontally(
                    targetOffsetX = { fullWidth -> -fullWidth },
                )
            },
            label = "Exercise View animation",
            modifier = Modifier.fillMaxSize(),
        ) { state ->
            Column(
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                //Composable
                Button(onClick = onClick) {
                    Text(text = state.number.toString())
                }
            }
        }
    }