kotlinnavigationandroid-jetpack-composeandroid-jetpack

Is there a way to cleanup navigation transition code in jetpack compose


I have the following code in my NavHost. The enterTransition, exitTransition, popEnterTransition and popExitTransition code is repeated for all the routes that I add to my NavHost. How do I clean it.

NavHost(
    navController = navController,
    startDestination = CreateProjectRoute,
) {
    composable<ProjectsListRoute>(
        enterTransition = {
            slideIntoContainer(
                AnimatedContentTransitionScope.SlideDirection.Left,
                tween(500)
            )
        },
        exitTransition = {
            slideOutOfContainer(
                AnimatedContentTransitionScope.SlideDirection.Left,
                tween(500)
            )
        },
        popExitTransition = {
            slideOutOfContainer(
                AnimatedContentTransitionScope.SlideDirection.Right,
                tween(500)
            )
        },
        popEnterTransition = {
            slideIntoContainer(
                AnimatedContentTransitionScope.SlideDirection.Right,
                tween(500)
            )
        }
    ) {
        ProjectsListScreen(
            onCreateButtonClicked = {
                navController.navigate(CreateProjectRoute)
            }
        )
    }
    composable<CreateProjectRoute>(
        enterTransition = {
            slideIntoContainer(
                AnimatedContentTransitionScope.SlideDirection.Left,
                tween(500)
            )
        },
        exitTransition = {
            slideOutOfContainer(
                AnimatedContentTransitionScope.SlideDirection.Left,
                tween(500)
            )
        },
        popExitTransition = {
            slideOutOfContainer(
                AnimatedContentTransitionScope.SlideDirection.Right,
                tween(500)
            )
        },
        popEnterTransition = {
            slideIntoContainer(
                AnimatedContentTransitionScope.SlideDirection.Right,
                tween(500)
            )
        }
    ) {
        CreateProjectScreen(
            viewModel = projectViewModel,
            navController = navController
        )
    }
}

I have tried creating functions like these:

fun defaultEnterTransition() = slideIntoContainer(
    AnimatedContentTransitionScope.SlideDirection.Left,
    tween(500)
)

and using them in nav routes like this:

composable<ProjectsListRoute>(
        enterTransition = { defaultEnterTransition() }
    ) { }

but I get the following error: Unresolved reference: slideIntoContainer


Solution

  • you can create your own extension function on NavGraphBuilder something like below and assign the default animation in the builder as you want.

    public inline fun <reified T : Any> NavGraphBuilder.slideComposable(
        typeMap: Map<KType, NavType<*>> = emptyMap(),
        noinline content: @Composable AnimatedContentScope.(NavBackStackEntry) -> Unit
    ) {
        destination(
            ComposeNavigatorDestinationBuilder(
                provider[ComposeNavigator::class],
                T::class,
                typeMap,
                content
            )
                .apply {
                    this.enterTransition = {
                        slideIntoContainer(
                            AnimatedContentTransitionScope.SlideDirection.Left,
                            tween(500)
                        )
                    }
                    this.exitTransition = {
                        slideOutOfContainer(
                            AnimatedContentTransitionScope.SlideDirection.Left,
                            tween(500)
                        )
                    }
                    this.popEnterTransition = {
                            slideIntoContainer(
                                AnimatedContentTransitionScope.SlideDirection.Right,
                                tween(500)
                            )
                        }
                    this.popExitTransition = {
                        slideOutOfContainer(
                            AnimatedContentTransitionScope.SlideDirection.Right,
                            tween(500)
                        )
                    }
                    this.sizeTransform = sizeTransform
                }
        )
    }
    
    
    NavHost(
            navController = navController,
            startDestination = LoginRoute,
            modifier = modifier,
        ) {
    
            slideComposable<LoginRoute> {
                LoginScreen(
                    navigateToDashboard = { navController.navigate(it) }
                )
            }
    
            slideComposable<DashboardRoute> { backStackEntry ->
                val route = backStackEntry.toRoute<DashboardRoute>()
                DashboardScreen(route)
            }
        }
    

    Now you can using slideComposable instead of composable in your nav graph.

    Note: Some other params like deeplinks, etc are missing you can add it as when needed.