Reputation: 561
I have 3 screens :
sealed class MyNavigation {
@Serializable
data class Home(
val id: Int
) : MyNavigation()
@Serializable
data object Detail : MyNavigation()
@Serializable
data object Final : MyNavigation() }
val navController = rememberNavController()
}
NavHost(
navController = navController,
startDestination = MyNavigation.Home(-1)) {
composable<MyNavigation.Home> {
//val id = it.savedStateHandle.get<Int>("id") ?: 0
HomeScreen(
id = id,
onNavigateToDetail = { navController.navigate(MyNavigation.Detail) }
)
}
composable<MyNavigation.Detail> {
DetailScreen(
onNavigateToFinal = { navController.navigate(MyNavigation.Final) }
)
}
composable<MyNavigation.Final> {
FinalScreen(
onNavigateBackToHome = { newId ->
/*
navController.getBackStackEntry(route = "packagename.MyNavigation.Home/{id}").savedStateHandle["id"] =
newId
navController.popBackStack(
"packagename.MyNavigation.Home/{id}",
inclusive = false
)*/
}
)
}
}
I would like to go back to Home Screen with an ID. How is it possible with new Navigation 2.8 ?
In comments, you have a "solution" but it does not use the new system. I don't want a solution with "sharedViewModel" too.
For screen with no arguments it works. For example if I write
navController.popBackStack(
route = MyNavigation.Detail,
inclusive = false
)
It works, but not for Home. Thanks !
Upvotes: 1
Views: 58
Reputation: 67248
Since you wish to navigate to first NavDestination
in your graph you can get it with
val startId = navController.graph.findStartDestination().id
navController.getBackStackEntry(startId).savedStateHandle["id"] = newId
navController.popBackStack(
destinationId = startId,
inclusive = false
)
If it's some NavDestination
in graph you could get it from current back stack
val backStack by navController.currentBackStack.collectAsState()
But it requires suppressing @SuppressLint("RestrictedApi")
And navigate with
val firstDestination: NavDestination? = backStack.firstOrNull {
it.destination.hasRoute(MyNavigation.Home::class)
}?.destination
firstDestination?.let {
val startId = firstDestination.id
navController.getBackStackEntry(startId).savedStateHandle["id"] = newId
navController.popBackStack(
destinationId = startId,
inclusive = false
)
}
Result
Full code
@SuppressLint("RestrictedApi")
@Preview
@Composable
fun PopUpBackStackWithResultSample() {
val navController = rememberNavController()
NavHost(
modifier = Modifier.fillMaxSize(),
navController = navController,
startDestination = MyNavigation.Home(-1),
) {
composable<MyNavigation.Home> { navBackstackEntry: NavBackStackEntry ->
val id = navBackstackEntry.savedStateHandle.get<Int>("id") ?: 0
HomeScreen(
id = id,
onNavigateToDetail = { navController.navigate(MyNavigation.Detail) }
)
}
composable<MyNavigation.Detail> {
DetailScreen(
onNavigateToFinal = { navController.navigate(MyNavigation.Final) }
)
}
composable<MyNavigation.Final> { navBackstackEntry: NavBackStackEntry ->
val backStack by navController.currentBackStack.collectAsState()
FinalScreen(
onNavigateBackToHome = { newId ->
val startId = navController.graph.findStartDestination().id
navController.getBackStackEntry(startId).savedStateHandle["id"] = newId
navController.popBackStack(
destinationId = startId,
inclusive = false
)
// Alternative for getting destination
/* val firstDestination: NavDestination? = backStack.firstOrNull {
it.destination.hasRoute(MyNavigation.Home::class)
}?.destination
firstDestination?.let {
val startId = firstDestination.id
navController.getBackStackEntry(startId).savedStateHandle["id"] = newId
navController.popBackStack(
destinationId = startId,
inclusive = false
)
}*/
}
)
}
}
}
@Composable
fun HomeScreen(id: Int, onNavigateToDetail: () -> Unit) {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
) {
Text("Home Screen Id: $id", fontSize = 32.sp)
Spacer(Modifier.weight(1f))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = onNavigateToDetail
) {
Text("Navigate to detail")
}
}
}
@Composable
fun DetailScreen(onNavigateToFinal: () -> Unit) {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp)
) {
Text("Detail Screen", fontSize = 32.sp)
Spacer(Modifier.weight(1f))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = onNavigateToFinal
) {
Text("Navigate to Final")
}
}
}
@Composable
fun FinalScreen(onNavigateBackToHome: (Int) -> Unit) {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp)
) {
Text("Final Screen", fontSize = 32.sp)
Spacer(Modifier.weight(1f))
Button(
modifier = Modifier.fillMaxWidth(),
onClick = dropUnlessResumed {
onNavigateBackToHome(5)
}
) {
Text("Popup back to Home")
}
}
}
Upvotes: 0
Reputation: 344
you could use
navController.previousBackStackEntry?.savedStateHandle?.set("key", "argumentValue")
navController.popBackStack()
On the previous destination:
val result = navController.currentBackStackEntry?.savedStateHandle?.get<String>("result")
LaunchedEffect(result) {
result?.let {
// Use the result
println("Received: $it")
}
}
alternatively you could use shared view model to pass the data back
Upvotes: 0