I'm working with with the Android Navigation Component (currently v2.1.0) and I'm trying to work out how best to handle a child screen needing its own BottomNavigationView, with the MainActivity already having a top level BottomNavigationView.
Google seem to really advocate for the Single Activity architecture for most cases. Here's how I presently have it:
- Main Activity
- NavHostFragment & Top Level BottomNav
NavHost has navGraph of main_navigation.xml: this has the MainActivity top level
bottom navigation fragments, (e.g. Groups, Courses, Profile etc.) and also a link to the child
fragment which should have its own BottomNav
- ChildFragment
- Has its own NavHostFragment in its layout, and its own BottomNav
This NavHost has navGraph of childfragment_navigation.xml: which, similar to MainActivity,
handles the bottom navigation fragments for the child fragment etc. etc.
This has presented a few problems. First of all, I'm having to show & hide the MainActivity BottomNavigationView if the user navigates into this child fragment, as follows:
private fun setupNavController() {
val navController = findNavController(R.id.nav_host_fragment)
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_groups, R.id.navigation_courses, R.id.navigation_profile
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
nav_view.setupWithNavController(navController)
navController.addOnDestinationChangedListener { _, destination, _ ->
when (destination.id) {
R.id.navigation_groups, R.id.navigation_courses, R.id.navigation_profile -> showBottomNavigation()
else -> hideBottomNavigation()
}
}
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.nav_host_fragment).navigateUp() || super.onSupportNavigateUp()
}
private fun hideBottomNavigation() {
nav_view.visibility = View.GONE
}
private fun showBottomNavigation() {
nav_view.visibility = View.VISIBLE
}
This feels really clunky, and a bit of a hack, and also starts to add some unwanted view logic into MainActivity.
The second issue is to do with the appbar and backstack stuff. Once I'm in the child fragment, I get the updated toolbar title for that child fragment, but then any further action bar updates don't work intially, and if I drill down into further child fragments, pressing back won't initially work other than taking me back to MainActivity. Adding app:defaultNavHost="true"
to both NavHostFragments seemed to solve some bits, namely the back button working properly once in the Child Fragment, although the app bar up button doesn't work for child fragments of the child fragment, it always goes back to MainActivity.
I tried putting this in the Child Fragment:
NavigationUI.setupActionBarWithNavController(activity as AppCompatActivity, navController)
This updates the toolbar title, but the up button still goes back to Main Activity.
There's 3 possible solutions I can think of to this structure of app (with child fragments having their own bottom nav):
- Give up on Single Activity architecture, and have the Child Fragment actually be its own Activity
- Just use one nav_graph, one NavHostFragment and one BottomNav, and figure out a way to swap out the BottomNavigation menu once in the child - any guidance on that would be appreciated
- Persist with this child fragment having its own NavHostFragment and BottomNav, and figure out a way to handle the back stack, the app bar, and the showing/hiding of the bottom navs