Ced*_*dar 5 android kotlin android-jetpack-navigation android-jetpack-compose jetpack-compose-navigation
所以我有两个选项卡,选项卡 A 和选项卡 B。每个选项卡都有自己的后堆栈。我使用此谷歌文档中的代码实现了多个返回堆栈导航
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
}
}
)
}
}
}
) {
NavHost(navController, startDestination = A1.route) {
composable(A1.route) {
val viewModelA1 = hiltViewModel()
A1(viewModelA1)
}
composable(A2.route) {
val viewModelA2 = hiltViewModel()
A2(viewModelA2)
}
composable(A3.route) {
val viewModelA3 = hiltViewModel()
A3(viewModelA3)
}
}
}
Run Code Online (Sandbox Code Playgroud)
选项卡 A 有 3 个屏幕(屏幕 A1 -> 屏幕 A2 -> 屏幕 A3)。我使用该函数实例化视图模型,并在每个屏幕的块hiltViewModel()
内调用它composable()
问题是当我从 A1 导航到 A2 再到 A3,然后当我将选项卡更改为选项卡 B 时,屏幕 A2 的视图模型似乎正在被处置(onCleared
被调用)。因此,当我返回到显示屏幕 A3 的选项卡 A,然后返回到屏幕 A2 时,A2 的视图模型将再次实例化(init
再次调用块)。我想要实现的是保留此流程的 A2 视图模型,直到我退出 A2。
这可能吗?
当您过快地单击下一个导航项而当前视图显示转换尚未完成时,这似乎是一个错误。这是一个已知问题,请为其加注星标以引起更多关注。
同时,您可以等待当前屏幕转换完成,然后再导航到下一个屏幕。为此,您可以检查visibleEntries
变量并仅在其仅包含单个项目后进行导航。
另外,我认为当前文档没有提供底部导航的最佳示例,因为如果您不在开始目标屏幕上,那么当我希望视图被关闭时,按后退按钮会将您带回到开始目的地。因此,我也改变了您的导航方式,如果您对文档行为感到满意,您可以fun navigate()
用您自己的内容替换 的内容。
val navController = rememberNavController()
var waitEndAnimationJob by remember { mutableStateOf<Job?>(null)}
Scaffold(
bottomBar = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
val scope = rememberCoroutineScope()
items.forEach { screen ->
fun navigate() {
navController.navigate(screen.route) {
val navigationRoutes = items
.map(Screen::route)
val firstBottomBarDestination = navController.backQueue
.firstOrNull { navigationRoutes.contains(it.destination.route) }
?.destination
// remove all navigation items from the stack
// so only the currently selected screen remains in the stack
if (firstBottomBarDestination != null) {
popUpTo(firstBottomBarDestination.id) {
inclusive = true
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
}
}
BottomNavigationItem(
icon = { Icon(Icons.Filled.Favorite, contentDescription = null) },
label = { Text(stringResource(screen.resourceId)) },
selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
onClick = {
// if we're already waiting for an other screen to start appearing
// we need to cancel that job
waitEndAnimationJob?.cancel()
if (navController.visibleEntries.value.count() > 1) {
// if navController.visibleEntries has more than one item
// we need to wait animation to finish before starting next navigation
waitEndAnimationJob = scope.launch {
navController.visibleEntries
.collect { visibleEntries ->
if (visibleEntries.count() == 1) {
navigate()
waitEndAnimationJob = null
cancel()
}
}
}
} else {
// otherwise we can navigate instantly
navigate()
}
}
)
}
}
}
) { innerPadding ->
// ...
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5420 次 |
最近记录: |