kotlinandroid-jetpack-composeandroid-jetpack-navigation

How to check if the current destination is top level in Jetpack Compose type-safe navigation?


I have a multibackstack navigation graph where each starting node for the bottom navigation is top level.

How can I check if I am currently in the top level destination in order to adjust the display of a UI element for example?

The following code sample does not solve the problem:

val isTopLevel = navController.previousBackStackEntry == null

Between top-level destinations, I navigate as follows:

navController.navigate(destination.route) {
    popUpTo(navController.graph.findStartDestination().id) {
        saveState = true
        inclusive = true
    }
    launchSingleTop = true
    restoreState = true
}

Solution

  • If you know top level NavDestinations that are not NavGraphs you can create a list and check if current destination is these top level list.

    For instance for this navigation

    navigation<BottomNavigationRoute.HomeGraph>(
        startDestination = BottomNavigationRoute.HomeRoute1
    ) {
        composable<BottomNavigationRoute.HomeRoute1> { from: NavBackStackEntry ->
            Screen(
                text = "Home Screen1",
                navController = nestedNavController,
                onClick = {
                    onBottomScreenClick(BottomNavigationRoute.HomeRoute2, from)
                }
            )
        }
    
        composable<BottomNavigationRoute.HomeRoute2> { from: NavBackStackEntry ->
            Screen(
                text = "Home Screen2",
                navController = nestedNavController,
                onClick = {
                    onBottomScreenClick(BottomNavigationRoute.HomeRoute3, from)
                }
            )
        }
    
        composable<BottomNavigationRoute.HomeRoute3> { from: NavBackStackEntry ->
            Screen(
                text = "Home Screen3",
                navController = nestedNavController
            )
        }
    }
    

    HomeRoute1 is NavDestination while HomeGraph is NavGraph.

    If you wish to do this dynamically you can check whether it's a NavGraph or NavDestination first.

        val nestedNavController = rememberNavController()
    
        val navBackStackEntry: NavBackStackEntry? by nestedNavController.currentBackStackEntryAsState()
        val currentDestination = navBackStackEntry?.destination
    
    
        val topLevelDestinations = remember {
            mutableStateListOf<NavDestination>()
        }
    
        currentDestination?.hierarchy?.let {
            if (topLevelDestinations.isEmpty()) {
                nestedNavController.graph.nodes.forEach { id, navDestination: NavDestination ->
                    if (navDestination is NavGraph) {
                        topLevelDestinations.add(navDestination[navDestination.startDestinationId])
                    } else {
                        topLevelDestinations.add(navDestination)
                    }
                }
            }
        }
    
    val topLevelDestination =
        topLevelDestinations.isNotEmpty() && topLevelDestinations.contains(currentDestination)