Reputation: 447
I'm trying to implement the following screen flow using Jetpack Compose + Jetpack Navigation:
Actually, i am able to code two singles cases:
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)
NavHost
without success.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
disappearsNavHost
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.
Upvotes: 7
Views: 9654
Reputation: 447
Ok, i found a solution. This are the steps to achieve the desired result:
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() }
}
}
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)
}
}
}
}
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
Upvotes: 11