【问题标题】:How can Jetpack Compose Navigation remember multiple back stacks?Jetpack Compose Navigation 如何记住多个返回堆栈?
【发布时间】:2023-02-21 05:59:21
【问题描述】:
我正在阅读 Jetpack Compose 中的导航,发现这个例子我不明白。
来自the docs:
通过使用 saveState 和 restoreState 标志,状态和返回堆栈当您在底部导航项目之间切换时,该项目的部分已正确保存和恢复。
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
items.forEach { screen ->
BottomNavigationItem(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.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
}
}
)
}
}
}
) { innerPadding ->
NavHost(navController, startDestination = Screen.Profile.route, Modifier.padding(innerPadding)) {
composable(Screen.Profile.route) { Profile(navController) }
composable(Screen.FriendsList.route) { FriendsList(navController) }
}
}
具体来说,我不明白如果单击底部栏中的项目弹出导航堆栈,如何保存返回堆栈to the root。
我会想象这样的旅程:
- 用户移动到
/FriendsList/Friend(A)/Friend(B)/Friend(C)
- 用户单击
Profile按钮,将导航堆栈重置为/Profile
- 用户点击
FriendsList按钮。
根据解释,我希望导航堆栈重新设置为/FriendsList/FriendA/FriendB/FriendC,即使onClick 侦听器似乎将堆栈设置为/FriendsList?
我真的不明白这是怎么发生的,导航控制器如何将路由链接到整个导航子堆栈? item.route 是否正在更改包含到 /FriendsList/Friend(A)/Friend(B)/Friend(C) 的完整路由的状态,或者是否发生了其他事情?还是我理解错了这个例子?
我怀疑潜在的机制可能是 FriendsList 包含嵌套导航图,因为该示例实际上并未显示任何 Friend 路由定义。整个嵌套图的状态以某种方式包含,即类似/FriendsList{FriendA/FriendB/FriendC} 的状态,移动到/FriendsList 将解压此导航堆栈。它是这样运作的吗?
【问题讨论】:
标签:
jetpack-compose-navigation
【解决方案1】:
我知道我的回答有点晚了,但这些天我一直在寻找具有相同行为的解决方案,最终我找到了一个。
要实现此行为,您需要声明嵌套的 navHosts。他们每个人都有自己的 navController,仅此而已。所有其余的都是自动工作的。
这是一个例子
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
Scaffold(
bottomBar = {
BottomNavigation {
items.forEach { screen ->
BottomNavigationItem(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
navController.navigate(screen.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
}
}
)
}
}
}
) { innerPadding ->
NavHost(
navController,
startDestination = Screen.ProfileNavHost.route,
Modifier.padding(innerPadding)
) {
composable(Screen.ProfileNavHost.route) {
val profileNavController = rememberNavController()
NavHost(
navController = profileNavController,
startDestination = Screen.ProfileRoot.route
) {
composable(Screen.ProfileRoot.route) {
ProfileRoot(navController)
}
composable(Screen.ProfileScreen.route) {
ProfileScreen(navController)
}
}
}
composable(Screen.FriendsListNavHost.route) {
val friendsListNavController = rememberNavController()
NavHost(
navController = friendsListNavController,
startDestination = Screen.FriendsListRoot.route
) {
composable(Screen.FriendsListRoot.route) {
FriendsList(navController)
}
composable(Screen.FriendsListFriend.route) {
FriendsListFriend(navController)
}
}
}
}
}
在上面的示例中,您还可以为配置文件选项卡设置一个后退堆栈,如果您不需要它,您可以从可组合项 (Screen.ProfileNavHost.route) 中删除 navHost 和 navController,然后调用您的 Screen 可组合项。