How to handle nested BottomNavigationView with Android Navigation Component?
Asked Answered
H

1

4

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):

  1. Give up on Single Activity architecture, and have the Child Fragment actually be its own Activity
  2. 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
  3. 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
Hopson answered 17/11, 2019 at 12:18 Comment(0)
P
2

You can follow Google single Activity architecture pattern but single navHostFragment and single navGraph can't save you, You need to use multiple navHost each has it's own navGraph so, each has it's own navigation. You need to switch between multiple navHostFragment and each has it's own navigation so it will work accourdingly.

You can take help from this [https://github.com/android/architecture-components-samples/blob/master/NavigationAdvancedSample/app/src/main/java/com/example/android/navigationadvancedsample/NavigationExtensions.kt.]

Presuppose answered 17/11, 2019 at 14:48 Comment(2)
I am trying to use this approach, but I could not find a way to navigate from one graph to a destination in the other graph. Example: - There are two options in the BottomNavigationView (Home and Accounts) - Home shows my favorites accounts and Accounts list all my account - If a click in one account in Account, it opens my account details How can I click in one account in Home (favorite account) and go straight to account details?Regnal
You can achieve this functionality using developer.android.com/guide/navigation/navigation-nested-graphs. by using nested navGraphs you can start you whole account flow from your "Home" section, and if you need only "account details" from "Home" then you need to specify your "action details" from in Home navigation graph. For further navigation related info you can check out developer.android.com/guide/navigation/…Presuppose

© 2022 - 2025 — McMap. All rights reserved.