3

I am trying to show thebottom bar navigation in only a few fragments (i.e hide it for most of my fragments)..

I read the official document about this, but it unclear to me, like where do I put the code, and I read comments on this here on StackOverFlow, like "I'm surprised this is suggested in the docs because it actually looks pretty terrible since the listener fires before the new fragment is placed on the screen, causing a visible flicker (that's sometimes there, sometimes not)".

I've research about this, and from my understanding I need to create a nested naviagtion_graph (navigation), or something, listen to onDestinationChanged and set bottom nav or toolbar to Gone..

I don't really understand this.. I just want to hide the bottom bar nav in most of the fragments..

Here's my navigation_gragh (mobile_navigation) :

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/mobile_navigation"
    app:startDestination="@+id/navigation_home">

    <fragment
        android:id="@+id/navigation_home"
        android:name="com.example.testingbottomnav.ui.home.HomeFragment"
        android:label="@string/title_home"
        tools:layout="@layout/fragment_home" >
        <action
            android:id="@+id/action_navigation_home_to_newScreenFragment"
            app:destination="@id/newScreenFragment" />
    </fragment>

    <fragment
        android:id="@+id/navigation_dashboard"
        android:name="com.example.testingbottomnav.ui.dashboard.DashboardFragment"
        android:label="@string/title_dashboard"
        tools:layout="@layout/fragment_dashboard" />

    <fragment
        android:id="@+id/navigation_notifications"
        android:name="com.example.testingbottomnav.ui.notifications.NotificationsFragment"
        android:label="@string/title_notifications"
        tools:layout="@layout/fragment_notifications" />
    <fragment
        android:id="@+id/newScreenFragment"
        android:name="com.example.testingbottomnav.ui.newscreen.NewScreenFragment"
        android:label="fragment_new_screen"
        tools:layout="@layout/fragment_new_screen" />
</navigation>

Here's my activity_main.xml :

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nav_view"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="0dp"
        android:layout_marginEnd="0dp"
        android:background="?android:attr/windowBackground"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:labelVisibilityMode="selected"
        app:menu="@menu/bottom_nav_menu" />

    <fragment
        android:id="@+id/nav_host_fragment_activity_main"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@id/nav_view"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />

</androidx.constraintlayout.widget.ConstraintLayout>

And here's my MainActivty.kt :

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val navView: BottomNavigationView = binding.navView

        val navController = findNavController(R.id.nav_host_fragment_activity_main)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications
            )
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }
}

Any help would be much appreciated, thanks..

Edwin
  • 565
  • 11
  • 26

5 Answers5

6

If you want to make visible your BottomNavigationView only if the destination is the top-level destination you can try:

 val appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.navigation_home, 
                R.id.navigation_dashboard, 
                R.id.navigation_notifications
            )
        )
 navController.addOnDestinationChangedListener { controller: NavController, destination: NavDestination, bundle: Bundle? ->
 yourBottomNavigationView.isVisible = appBarConfiguration.topLevelDestinations.contains(destination.id)
}
Jarnojr
  • 543
  • 1
  • 7
  • 18
2

The easy way to fix this is to create a method in your MainActivity which allows you to show/hide the BottomNavigationView. Open the MainActivity.kt class and add the following methods to it.

fun showBottomNavigation()
{
    bottomNavView.visibility = View.VISIBLE
}

fun hideBottomNavigation()
{
    bottomNavView.visibility = View.GONE
}

Now, call these methods from the Fragment you want to hide BottomNavigationView like this.

override fun onAttach(context: Context) {
    super.onAttach(context)
    (activity as MainActivity).hideBottomNavigation()
}

override fun onDetach() {
    (activity as MainActivity).showBottomNavigation()
    super.onDetach()
}
mdoflaz
  • 551
  • 6
  • 19
  • 1
    +1. Worked. I put them on `onStart` instead. Also, if you have FAB button in BottomNavigationView, hide it like BottomNavigationView. – C.F.G Jul 03 '23 at 10:33
1

First set up your navigation after that add a destination change listener to the nav controller. Whenever you navigate to a fragment navController.navigate(/* Some Destination Id */) the destination change listener will fire up there you can check and compare if you want to show or hide the bottom navigation or toolbar.

private fun setupBottomNavigation() {

        val navHostFragment = supportFragmentManager
            .findFragmentById(R.id.fragment_container_view) as NavHostFragment?

        if (navHostFragment != null) {

            navController = navHostFragment.navController

            setupWithNavController(binding!!.navView, navController!!)

            initDestinationListener()

        }
    }

    private fun initDestinationListener() {

        navController!!.addOnDestinationChangedListener { controller: NavController?, destination: NavDestination, bundle: Bundle? ->

            // Showing or Hiding Bottom Navigation on Specific Screen
            
            if (destination.id == R.id.navigation_plan ||
                destination.id == R.id.navigation_video ||
                destination.id == R.id.navigation_about ||
                destination.id == R.id.navigation_detail ||
                destination.id == R.id.navigation_contact ||
                destination.id == R.id.navigation_privacy ||
                destination.id == R.id.navigation_comments
            ) {

                hideBottomNavigation()

            } else {

                showBottomNavigation()

            }
        }
    }
Malik Bilal
  • 869
  • 8
  • 25
  • Thanks for your answer Malik.. But what are the "R.id.navigation_plan" and others, are they fragment I want to hide the bottom bar nav?? – Edwin Jan 18 '22 at 23:06
  • 1
    @Edwin they are the ids of the fragments in the navigation graph. If you want to hide bottom navigation on a fragment add their id to the if condition. – Malik Bilal Jan 18 '22 at 23:37
  • I'm getting an unresolved error for hideBottomNavigation() and showBottomNavigation().. How do I correct this please.. – Edwin Jan 19 '22 at 01:33
  • Thanks a lot Malik for your help, I have been able to resolved the issue.. – Edwin Jan 19 '22 at 02:33
1

I added this line of code to the onCreate method:

// hiding bottom bar
    navController.addOnDestinationChangedListener { _, nd: NavDestination, _ ->
        // the IDs of fragments as defined in the `navigation_graph`
        if (nd.id == R.id.navigation_home || nd.id == R.id.navigation_dashboard
            || nd.id == R.id.navigation_notifications
        ) {
            navView.visibility = View.VISIBLE
        } else {
            navView.visibility = View.GONE
        }
    }
Edwin
  • 565
  • 11
  • 26
1

you can write a method to init the navigation in your activity and hide navigation in this method and use it in onCreate() like this:

 private fun setupNavigation() {
    val navController = findNavController(R.id.nav_host_fragment_activity_main)
    navView.setupWithNavController(navController)
    navController.addOnDestinationChangedListener { controller, destination, arguments ->
        when (destination.id) {
            R.id.fragment1 -> bottomNavigation.visibility = View.VISIBLE
            R.id.fragment2 -> bottomNavigation.visibility = View.VISIBLE
            R.id.fragment3 -> bottomNavigation.visibility = View.VISIBLE
            else -> bottomNavigation.visibility = View.GONE
        }
    }
}

this code show navigation in fragment 1 ,2 ,3 and hide it for another fragment