androidkotlinandroid-jetpack-composeandroid-jetpack-compose-navigation

Pass Nav Augments to enter Transition arguments in android compose navigation


I’ve got a Navigation compose that passes arguments to the start animation, specifically the scaleIn and scaleOut properties. However, the offSetX and offSetY values are null.

But here’s the catch: when I access these values from it.arguments, they show the correct values. Can you help me understand why this is happening?

composable(
    route = NavigationRoute.PreviewImage.route,
    deepLinks = listOf(navDeepLink { uriPattern = "suntuk://preview/{id}/{type}/{x}/{y}" }),
    arguments = listOf(
        navArgument("id") { type = NavType.StringType },
        navArgument("type") { type = NavType.IntType },
        navArgument("x") { type = NavType.FloatType },
        navArgument("y") { type = NavType.FloatType }
    ),
    enterTransition = {
        val offsetX = initialState.arguments?.getFloat("x") ?: 0f
        val offsetY = initialState.arguments?.getFloat("y") ?: 0f
        scaleIn(
            animationSpec = tween(durationMillis = 5000),
            transformOrigin = TransformOrigin(
                offsetX,
                offsetY
            )
        )
    },
    exitTransition = {
        val offsetX = initialState.arguments?.getFloat("x") ?: 0f
        val offsetY = initialState.arguments?.getFloat("y") ?: 0f
        Timber.i("Offset: $offsetX, $offsetY")
        scaleOut(
            animationSpec = tween(durationMillis = 5000),
            transformOrigin = TransformOrigin(
                offsetX,
                offsetY
            )
        )
    }
) {
    val id = it.arguments?.getString("id") ?: ""
    val type = it.arguments?.getInt("type") ?: 0
    val x = it.arguments?.getFloat("x") ?: 0f
    val y = it.arguments?.getFloat("y") ?: 0f
    Timber.i("Preview image: $id, $type, $x, $y")
    val viewModel: PreviewImageViewModel = koinViewModel { parameterSetOf(id, type) }

    PreviewImageScreen(
        viewModel = viewModel,
        onBack = {
            navController.navigateUp()
        }
    )
}

Solution

  • The enterTransition goes from an initialState - the screen you were at before going to this destination to the targetState - the screen you are going to be on when the transition ends. That means that you should be reading arguments from the targetState if you want it to be the instance of your NavigationRoute.PreviewImage.route:

    enterTransition = {
        val offsetX = targetState.arguments?.getFloat("x") ?: 0f
        val offsetY = targetState.arguments?.getFloat("y") ?: 0f
    

    However, if you're trying to key the animation off of an element in the previous screen, what you actually want to use is the shared element APIs where the element in your list on the previous screen as the same key as the whole screen in your other screen, thus causing the transition to animate out from the list item selected.