Jetpack Compose - Using Nested NavGraph with BottomNavBar and make Icons selected

Viewed 58

I want to implement a BottomNavBar with 3 items. Each navigating to a new navGraph. (Nested Navigation)

Home = "HomeGraph"

Explore = "ExploreGraph"

Profile = "ProfileGraph"

HomeGraph:

@OptIn(ExperimentalAnimationApi::class)
fun NavGraphBuilder.addHomeGraph(navController: NavHostController) {

    navigation(
        startDestination = "feed",
        route = "HomeGraph"
    ) {
        composable(
            route = "feed"
        ) {
        }
        composable(
            route = "comments"
        ) {
        }

    }
}

And my BottomNavBar navigates between those 3 graphs:

@Composable
fun BottomNavigationBar(navController: NavController) {
    val items = listOf(
        BottomNavigationItem.HomeGraph,
        BottomNavigationItem.ExploreGraph, 
        BottomNavigationItem.ProfileGraph
    )

    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentRoute = navBackStackEntry?.destination?.route 


    BottomNavigation() { 
        Row(horizontalArrangement = Arrangement.Center) {

            items.forEach { item ->  
                BottomNavigationItem(
                    icon = {
                        if (currentRoute == item.route) {
                            Icon(
                                painterResource(id = item.iconPressed),
                                contentDescription = item.title
                            )
                        } else {
                            Icon(
                                painterResource(id = item.iconNormal),
                                contentDescription = item.title
                            )
                        }
                    },
                    selectedContentColor = MaterialTheme.colors.primary,
                    unselectedContentColor = MaterialTheme.colors.onSurface,
                    alwaysShowLabel = false,
                    selected = currentRoute == item.route,
                    onClick = {
 
                        navController.navigate(item.route) {

                            navController.graph.startDestinationRoute?.let { route ->
                                popUpTo(route) {
                                    saveState = true
                                }
                            }
                            launchSingleTop = true
                            restoreState = true
                        }
                    }
                )
            }

        }
    }
}

Now the problem is that my "Home" BottomNav Icon is not changing cause "selected" is never true.

selected = currentRoute == item.route,

How can I check if I am still on the same navigationGraph? So when I go down the "HomeGraph" for example to "feed" or "comments" it should still indicate the "Home" Icon on my BottomNavBar as selected.

"feed" and "Comments" have in common, that their parent NavGraph is called "HomeGraph", how can I check for that?

With other words: I want pretty much the same BottomNavBar behaviour as Instagram

1 Answers

Instead of matching navBackStackEntry?.destination?.route, try looking for your route in the NavDestination's hierarchy.

val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination

Then in your forEach:

val selected = currentDestination?.hierarchy?.any { it.route == item.route } == true
Related