Simon Stahl
06/16/2022, 1:50 AMpage/{pageName}
).
Questions:
1. currentDestination?.hierarchy
does not contain the root tab name after navigating to a sub page, so the tab does not stay selected
2. I would like to change the back behavior. By default, back first pops the current tabs backstack. Once it is empty, it moves to the startDestination
(root page in the first tab with backstack empty). I would like to change that to: pop backstack of current tab. Once empty, switch to last used tab including backstack and start popping there. Once empty switch to the next last used tab etc. If there are no more backstack entries, close the app.
For reference, please find my sample code in the commentsprivate val bottomNavTabs = listOf("For You", "Profile", "Whatever")
fun getBottomNavTabs() = bottomNavTabs // in reality this would come from a server call
@Composable
fun NavigationTest() {
val navController = rememberNavController()
val bottomNavTabs = remember { getBottomNavTabs() }
Scaffold(
bottomBar = { SimpleBottomNav(navController, bottomNavTabs) }
) { innerPadding ->
NavHost(
navController,
startDestination = bottomNavTabs[0],
Modifier.padding(innerPadding)
) {
val navigateToSubPage: (String) -> Unit = { pageName -> navController.navigate("page/$pageName") }
// Known bottom nav tab destinations
bottomNavTabs.forEach { pageName ->
composable(pageName) {
PageContent(pageName, navigateToSubPage)
}
}
// Unknows sub pages
composable("page/{pageName}") {
val pageName = it.arguments?.getString("pageName")
pageName?.let { pn -> PageContent(pn, navigateToSubPage) }
}
}
}
}
// Create some random page with a LazyList to test page state preservation
@Composable
fun PageContent(name: String, onNavigate: (pageName: String) -> Unit) {
Column(modifier = Modifier.fillMaxSize()) {
Text(text = "Page: $name")
var text by rememberSaveable { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it })
Button(onClick = { if (text.isNotEmpty()) onNavigate(text) }) {
Text(text = "Open page $text")
}
LazyColumn {
items(100) {
Text(
modifier = Modifier
.fillMaxWidth()
.padding(5.dp)
.background(Color.LightGray),
text = "Column $it"
)
}
}
}
}
@Composable
fun SimpleBottomNav(navController: NavHostController, tabNames: List<String>) {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
tabNames.forEach { pageName ->
BottomNavigationItem(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
label = { Text(pageName) },
// Hier currentDestination?.hierarchy does not contain the tab name once on a sub page
selected = currentDestination?.hierarchy?.any { it.route == pageName } == true,
onClick = {
navController.navigate(pageName) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
}
)
}
}
}
Ian Lake
06/16/2022, 2:12 AMSimon Stahl
06/16/2022, 3:24 AMpopUpTo
, the issue i ran into then is that the compose states are not saved anymore and every time i switch tab etc, the composables are in their default stateIan Lake
06/16/2022, 3:54 AMColton Idle
06/16/2022, 3:17 PMSimon Stahl
06/16/2022, 5:57 PM