androidandroid-studioandroid-jetpack-compose

Can Jetpack Compose preserve navigation states across NavigationBar tabs like Google Chat App?


I'm building a tabbed interface with stacked screens using Jetpack Compose Navigation and a NavigationBar. I'm navigating to the selected tab using LaunchEffect when a NavigationBar component is clicked. However, the back button is taking me back to the previous tab, which isn't the intended behavior. I'd like the back button to navigate back to the previous Activity or a stacked composable in the same tab.

Additionally, I want to preserve the state of composables within a tab when switching to another tab, similar to Google Chat App.

Could you please provide some guidance?

val navController = rememberNavController()
var selectedTab by remember { mutableIntStateOf(0) }

Scaffold(
    bottomBar = {
        // set navigation bar components
        NavigationBar {
            NavigationTab.entries.forEachIndexed { index, item ->
                NavigationBarItem(
                    icon = { Icon(item.icon, contentDescription = item.label) },
                    label = { Text(item.label) },
                    selected = selectedItem == index,
                    onClick = { selectedItem = index }
                    )
                }
            }
        }) { 
            innerPadding ->

            NavHost(navController = navController, startDestination = "tab1") {
                // When an item is selected on Tab1Screen, the navController navigates to the Tab1Sub screen. 
                composable("tab1") { Tab1Screen(navController, innerPadding) }
                composable("tab1/{id}") { backStackEntry ->
                    val id = backStackEntry.arguments?.getString("id")
                    Tab1SubScreen(id, innerPadding)
                }
                composable("tab2") { Tab2Screen() }
                composable("tab3") { Tab3Screen() }
            }
        }

        LaunchedEffect(selectedTab) {
            when (selectedTab) {
                0 -> navController.navigate("tab1")
                1 -> navController.navigate("tab2")
                2 -> navController.navigate("tab3")
            }
        }


Solution

  • This question is answered in the docs.

    navController.navigate(topLevelRoute.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(navController.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
        }
    

    You didn't ask for it, but i can't help adding a few comments on codestyle: