7

I'm trying to implement the following screen flow using Jetpack Compose + Jetpack Navigation:

Navigation concept

Actually, i am able to code two singles cases:

  • SplashScreen --> HomeScreen (with no BottomNavBar)
  • HomeScreen (with BottomNavBar) --> Tabs

I'm not able to code the whole problem. In fact, i have an issue with the management of the NavHost. In the first case (SplashScreen -> HomeScreen) i need to call the NavHost at a high scope:

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
        MyAppTheme {
            //init the Navigation Controller for screen navigation
            val navController = rememberNavController()

            //setup the Navigation Graph
            SetupNavGraph(navController)

while in the second case i need to call it in the innerPadding scope of the Scaffold composable:

fun MainScreen(navController: NavHostController) {

    Scaffold(
        bottomBar = {
            BottomNavBar(navController)
        }
    ) { //innerPadding scope
        //setup the Navigation Graph
        SetupNavGraph(navController)
    }
}

Please assume that SetupNavGraph() function works as intended (call NavHost to generate the navigation tree)

  • I tried to use two NavHost without success.
  • If i setup the NavHost in setContent() i'm able to load the splashscreen and move to an empty BottomNavBar screen. If i click on the BottomNavElements i'm able to navigate to the child tabs (in the example above "Favorite","Music","Places", "News") but the BottomNavBar disappears
  • I cannot setup NavHost in the innerPadding scope because this is loaded only after switching to the main screen (in the example above "Favorite Tab" + BottomBarNav)

The only workaround i found is generating the BottomNavBar composable in each of the BottomNav child tabs, but this generates a visible transition effect that i would like to avoid and, generally, doesn't seem a good practice.

3
  • Sorry I couldn't understand the question Commented Feb 11, 2022 at 0:38
  • Sorry and thx for editing. I added a more complete explanation and an example image of what i would like to achieve. Even if you can't answer, for the sake of being clear, could you tell me if what i ask is now understandable? Thx! Commented Feb 11, 2022 at 8:05
  • Yeah, It's now clear Commented Feb 11, 2022 at 12:43

1 Answer 1

11

Ok, i found a solution. This are the steps to achieve the desired result:

  1. Create two different NavGraph, one for Splash->MainScreen and the other for the BottomNavBar
const val ROOT_ROUTE = "root"

@Composable
fun SetupRootNavGraph(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = Screen.FirstScreen.route,
        route = ROOT_ROUTE
    ) {
        composable(Screen.FirstScreen.route) { FirstScreen(navController)}
        composable(Screen.SecondScreen.route) { MainScreen(navController)}
    }
}
const val BOTTOM_BAR_ROUTE = "bottomBar"

@Composable
fun SetupNavGraphBottomBar(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = BottomBarScreen.FirstElement.route,
        route = BOTTOM_BAR_ROUTE
    ) {
        composable(BottomBarScreen.FirstElement.route) { FirstElementScreen() }
        composable(BottomBarScreen.SecondElement.route) { SecondElementScreen() }
        composable(BottomBarScreen.ThirdElement.route) { ThirdElementScreen() }
    }
}
  1. Init the NavController and the RootNavGraph after setContent() in your MainActivity. This will be in charge of the SplashScreen -> MainScreen navigation tree.
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyAppTheme {

                //init the Navigation Controller for screen navigation
                val navController = rememberNavController()

                //setup the Root Navigation Graph
                SetupRootNavGraph(navController)
            }
        }
    }
}
  1. Re-init the NavController in the Screen where you have your BottomNavBar ("MainScreen" in the example) and the assign to it the BottomNavGraph in the innerPadding scope.
@Composable
fun MainScreen(navController: NavHostController) {

    //Re-initialize the NavController to set a new NavGraph
    val navControllerBottomBar = rememberNavController()

    Scaffold(
        bottomBar = {
            BottomNavBar(navControllerBottomBar)
        }
    ) {
        //setup the Navigation Graph
        SetupNavGraphBottomBar(navControllerBottomBar, user)
    }
}

And this will work like charm! Of course you will need to structure your BottomNavBar in order to manage the navigation as documented on Official docs

Sign up to request clarification or add additional context in comments.

5 Comments

Question: Your MainScreen is part of which Graph? ROOT_ROUTE or BOTTOM_BAR_ROUTE ?
You found me at the end. :) It's root route. Btw, I suggest you to read another similar post. This solution is not the best if you have that a tab of the bottomnav need to navigate to a screen without bottomnav.
stackoverflow.com/questions/71395630/… this is the post I suggest you to read
But you lose the ability to navigate between the two graphs right? How do you go from the BottomNavGraph back to the MainNavGraph. EG if the main graph was a login flow, when your session expires one would want to navigate from the bottom graph back to the main graph
You are absolutely right. Unfortunately I was not able to find a solution with nested navigation. I prefer the solution in the other post (the other one you commented) because is more consistent and organized, even if it's still more a workaround than a solution

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.