HavanaSun
HavanaSun

Reputation: 936

Navigate the BottomNavBar on Button click - Jetpack Compose

My BottomNavigationBar has 4 items, I want to navigate to the last item when the user clicks a button.

Here is my BottomNavigationBar:

@Composable
fun BottomNavigationBar(navController: NavController) {
    val items = listOf(
        BottomNavigationItem.Home,
        BottomNavigationItem.Explore,
        BottomNavigationItem.Favorites,
        BottomNavigationItem.Profile
    )

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

    BottomNavigation(
        backgroundColor = colorResource(id = R.color.purple_700),
        contentColor = Color.White
    ) {

        Row(horizontalArrangement = Arrangement.Center) {
 
            items.forEachIndexed { i, item ->
                if (i == items.count() / 2) {
                    Spacer(Modifier.weight(1f))
                }
                BottomNavigationItem(
                    icon = {
                        if (currentRoute == item.route) {
                            Icon(painterResource(id = item.iconPressed), contentDescription = item.title)
                        } else {
                            Icon(painterResource(id = item.iconNormal), contentDescription = item.title)
                        }
                    },
                    selectedContentColor = Color.White,
                    unselectedContentColor = Color.White,
                    alwaysShowLabel = false,
                    selected = currentRoute == item.route,
                    onClick = { 
                        navController.navigate(item.route) { 
                            navController.graph.startDestinationRoute?.let { route -> 
                                popUpTo(route) { 
                                    saveState = true
                                }
                            } 
                            launchSingleTop = true
                             restoreState = true
                        }
                    }
                )
            }

        }
    }
}

and here is how I try to navigate to the "Profile" screen when the user clicks a button (in my MainActivity NavGraph):

     composable(BottomNavigationItem.Favorites.route) {
         
        FavoriteScreen(navigateToProfile = {
            navController.navigate(BottomNavigationItem.Profile.route) {
                        popUpTo(navController.graph.findStartDestination().id) {
                            saveState = true
                        }
                        launchSingleTop = true
                        restoreState = true
                    }
        })
    }                       

Unfortunately this gives me a weird behaviour that my BottomNavigationBar is not working correctly, mostly the first screen is not opening anymore.

Something is getting mixed up and the "HomeScreen" bottomNavItem navigates to the "ProfileScreen" after the remote navigation.

What is the correct way to remotely navigate the bottomNavigationBar?

Upvotes: 3

Views: 1579

Answers (1)

sschmitz
sschmitz

Reputation: 442

After several hours of struggling with a similar issue myself, I eventually created a bug report and a sample project demonstrating this issue. It was marked as a duplicate and not a bug.

If you want to emulate swapping to another tab, make sure to use the exact same flags as your BottomNav uses to actually swap from the back stack associated with one tab to the back stack associated with the other tab.

So, what I've decided to do since then is extend NavHostController and just always call switchTabs from both inside of my BottomNavigationItem.onClick and from any buttons that I would like to result in the tab switching.

fun NavHostController.switchTabs(route: String) {
  navigate(route) {
    // Pop up to the start destination of the graph to
    // avoid building up a large stack of destinations
    // on the back stack as users select items
    popUpTo(graph.findStartDestination().id) {
      saveState = true
    }
    
    // Avoid multiple copies of the same destination when
    // reselecting the same item
    launchSingleTop = true

    // Restore state when reselecting a previously selected item
    restoreState = true
  }
}

For me this has resulted in a much more sane navigation structure and has removed all of my issues where tapping on the bottom nav would appear unresponsive.

Upvotes: 1

Related Questions