Is nested navhost good? I have a 3 screens. Lets s...
# compose-android
r
Is nested navhost good? I have a 3 screens. Lets says SplashScreen and then HomeScreen which hosts bottom navigation bar and drawer. I also have some details screens. So splash screen and detail screens don't need bottombar and drawer. So i used Root NavHost to host these 3 screens and inside HomeScreen i have Bottombar drawer and scaffold with its own navhost. Can i do better here in terms of using single navhhost?
Found this https://itnext.io/compose-navigation-a-great-choice-for-large-android-apps-94c02984acd5 if you look at the bottom bar section here my set up is very similar.
i
No, a nested nav host has never been the recommended pattern for this kind of use case. Previously, you'd use your current destination to conditionally show/hide these kind of controls that you only want on certain screens, but nowadays you'd use shared elements, something we just recently discussed over in this other thread: https://kotlinlang.slack.com/archives/C06CS4UCQ10/p1719588491485179?thread_ts=1719554859.324029&cid=C06CS4UCQ10
👀 1
r
I went down the path of using conditional showing of bottom bar and drawer based on current Navigation route. But i will explore shared element transition!
Does jet snack use the shared element transition to show and hide bottom bar with animated visibility?. Exploring more on this in my free time.
Copy code
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun SimpleJetsnackApp() {
    val navController = rememberNavController()
    SharedTransitionLayout {
        CompositionLocalProvider(
            LocalSharedTransitionScope provides this
        ) {
            NavHost(navController = navController, startDestination = "home") {
                composable("home") {
                    CompositionLocalProvider(
                        LocalNavAnimatedVisibilityScope provides this
                    ) {
                        HomeScreen(onSnackSelected = { navController.navigate("detail") })
                    }
                }
                composable(
                    "detail",
                ) {
                    DetailScreen()
                }
            }
        }
    }
}




@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun HomeScreen(onSnackSelected: () -> Unit) {
    val sharedTransitionScope = LocalSharedTransitionScope.current
        ?: throw IllegalStateException("No SharedElementScope found")
    val animatedVisibilityScope = LocalNavAnimatedVisibilityScope.current
        ?: throw IllegalStateException("No SharedElementScope found")
    Scaffold(
        bottomBar = {
            with(animatedVisibilityScope) {
                with(sharedTransitionScope) {
                    NavigationBar(
                        modifier = Modifier
                            .renderInSharedTransitionScopeOverlay(zIndexInOverlay = 1f)
                    ) {
                        NavigationBarItem(
                            icon = { Icon(Icons.Filled.Home, contentDescription = "Home") },
                            label = { Text("Home") },
                            selected = true, // You'll need to manage the selected state
                            onClick = { /*TODO*/ }
                        )
                        NavigationBarItem(
                            icon = { Icon(Icons.Filled.Settings, contentDescription = "Settings") },
                            label = { Text("Settings") },
                            selected = false, // You'll need to manage the selected state
                            onClick = { /*TODO*/ }
                        )
                    }
                }
            }
        }
    ) { innerPadding ->

            Column(
                modifier = Modifier
                    .padding(innerPadding)
                    .fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Button(onClick = onSnackSelected) {
                    Text("Go to Detail")
                }
            }

    }
}

@Composable
fun DetailScreen() {
    // Detail screen content
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.LightGray),
        contentAlignment = Alignment.Center
    ) {
        Text("Detail Screen")
    }
}

val LocalNavAnimatedVisibilityScope = compositionLocalOf<AnimatedVisibilityScope?> { null }
@OptIn(ExperimentalSharedTransitionApi::class)
val LocalSharedTransitionScope = compositionLocalOf<SharedTransitionScope?> { null }
A very basic implementation based on jet snack.
👍 1