26

How can I add Fragment Change Listener in new Navigation Component?

I have a BottomNavigationView in which I used new Navigation Component following official sample

I have four destinations in my BottomNavigationView, all of them have their navigation graphs.

val navGraphIds = listOf(R.navigation.nav_home, R.navigation.nav_discover, R.navigation.nav_search, R.navigation.nav_my)

val controller = bottom_nav.setupWithNavController(
    navGraphIds = navGraphIds,
    fragmentManager = supportFragmentManager,
    containerId = R.id.navHostContainer,
    intent = intent
)

controller.observe(this, Observer { navController ->
    setupActionBarWithNavController(navController)
})

I want to have a listener in my MainActivity when fragment changed in any of 4 navigation graphs.

the controller is only affective when switching between BottomNavigationView destinations.

musooff
  • 6,412
  • 3
  • 36
  • 65

2 Answers2

59

Have you tried NavController.OnDestinationChangedListener?

private lateinit var controller: NavController // don't forget to initialize

private val listener = NavController.OnDestinationChangedListener { controller, destination, arguments ->
    // react on change
    // you can check destination.id or destination.label and act based on that
}

override fun onResume() {
    super.onResume()
    controller.addOnDestinationChangedListener(listener)
}

override fun onPause() {
    controller.removeOnDestinationChangedListener(listener)
    super.onPause()
}
Vlad
  • 7,997
  • 3
  • 56
  • 43
Marat
  • 6,142
  • 6
  • 39
  • 67
  • 6
    // don't forget to initialize --> Part will be `navController = Navigation.findNavController(this, R.id.nav_host_fragment)` , where nav_host_fragment is fragment which contains `app:navGraph="@navigation/mobile_navigation"` – Rahul Kahale Mar 06 '20 at 11:26
  • 1
    Does it have to be added and removed? Why can't it just be added in onCreate and left there? – behelit Jun 26 '22 at 23:57
  • I have a question: shouldn't the listener also be removed in `onDestroy()`? Something like that: `override fun onDestroy() { controller.removeOnDestinationChangedListener(listener) super.onDestroy() }` – A. Cedano May 05 '23 at 19:08
1

Addition to marat and vlad answers , if u use FragmentContainer in Xml , you can access it's nav controller by this :

val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment 
val navController = navHostFragment.navController

else may encounter IllegalStateException of acitivity dont have navcontroller

Aslm Monir
  • 51
  • 3