Infinito Nirone 7

白羽の矢を刺すスタイル

BottomNavigationView で setupWithNavController と setOnNavigationItemSelectedListener を同時に使いたい

Android Jetpack の Navigation Component と BottomNavigationView を組み合わせる場合、setupWithNavController 拡張関数を呼びだすだけで nav graph と BottomNavigationView の menu を紐付けてくれるようになります。

val navView: BottomNavigationView = ...
val navController: NavController = ...

navView.setupWithNavController(navController)

ここで、BottomNavigationView の menu を選択したときにコールバックを受けたい場合、次のように setOnNavigationItemSelectedListener を使ったコードを書くと BottomNavigationView の menu と nav graph の紐付けが壊れて画面の切り替えができなくなります。 setupWithNavController 拡張関数は内部で setOnNavigationItemSelectedListener を使って BottomNavigationView の menu を選択したときの処理を記述しているため、次のコードはその処理を上書きしてしまい、その結果画面の切り替えができなくなります。

val navView: BottomNavigationView = ...
val navController: NavController = ...

navView.setupWithNavController(navController)
navView.setOnNavigationItemSelectedListener { menu ->
  // Callback
  Log.d("Sample", "$menu is selected!!!")
  true
}

NavController の addOnDestinationChangedListener を使って各 menu に対応する destination に切り替わったことを検知するロジックを作ると、BottomNavigationMenu の menu を選択したときのコールバックと同等の機能が実現できます*1。 もし setOnNavigationItemSelectedListener を使いたい場合は、次のように setupWithNavController の実装を持ってくる必要があります。

val navView: BottomNavigationView = ...
val navController: NavController = ...

navView.setupWithNavController(navController)
navView.setOnNavigationItemSelectedListener { menu ->
  // Callback
  Log.d("Sample", "$menu is selected!!!")  
  NavigationUI.onNavDestinationSelected(menu, navController) // この部分が setupWithNavController でやっていること
}