Tonio
Tonio

Reputation: 561

Going back to the Home screen with arguments

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

Answers (2)

Thracian
Thracian

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

enter image description here

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

ayman omara
ayman omara

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

Related Questions