NavigationとFragmentとToolbarと
前置き
AndroidにはToolbarと呼ばれる部分があります。(SnazzyAppと書かれた部分です。)
ここにはハンバーガメニューだったり、アプリ名だったり、メニューだったりと、様々な情報を表示するのに使います。
そして、このtoolbarを扱うAPIはActivityに生えています。
Jetpack composeのNavigationの登場により、Fragmentを遷移させて画面遷移を実現させる方法が増えてきたと思います。画面によって、toolbarの中身を変えたい。画面によってはtoolbarを消したい。と言ったニーズが私の中で出てきました。今回はその解決方法を考えてみました。
解決方法
・ToolbarはActivityに置く
・MenuはFragmentで管理する
・Activityが現在の画面を認識するためにfindNavController().addOnDestinationChangedListenerを使用し、その中でtoolbarを出したり消したりする
ToolbarはActivityに置く
ActivityにはNavHostFragmentのコンテナfragmentがあると思います。一緒にToolbarも置いておきます。そして、toolbarに機能を追加するために、setSupportActionBar()を呼びます。ここまでは普通のtoolbarと同じです。
MenuはFragmentで管理する
FragmentでtoolbarのMenuを管理するためには、setHasOptionsMenu(true)を呼びます。そうすると、FragmentのメソッドであるonCreateOptionsMenu()が呼ばれるので、inflater.inflate(R.menu.hoge, menu)で設定してください。設定されたmenuが選択されたら、onOptionsItemSelected()が呼ばれます。この辺りはActivityの場合と同じです。
class HogeFragment: Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
setHasOptionsMenu(true)
// 以下略
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater: MenuInflater = menuInflater
inflater.inflate(R.menu.game_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle item selection
return when (item.itemId) {
R.id.new_game -> {
newGame()
true
}
R.id.help -> {
showHelp()
true
}
else -> super.onOptionsItemSelected(item)
}
}
}
Activityが現在の画面を認識するためには
Navigationで画面遷移を管理していると、遷移した時のイベントを拾うことができます。findNavController().addOnDestinationChangedListenerで遷移先のdestinationを拾うことができるので、navigation_graph.xmlのdestination_idと等しいものに遷移したことになります。
ここまで分かれば、toolbarが不要なfragmentに遷移したらtoolbar.visibility = View.GONEとすれば良いし、必要ならtoolbar.visibility = View.VISIBLEとすればokです。
class HogeActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
this.nav_fragment.findNavController().addOnDestinationChangedListener { _, destination, _ ->
when(deestination.id) {
R.id.hogeFragment -> {}
}
}
}
}
検討したけど採用しなかった方法
fragmentからactivityを操作する
fragmentからactivityを操作して、toolbarをsetSupportActionBar()に登録する方法も考えました。
ですが、activityがtoolbarを持っていることをfragmentが知っているのは依存の方向性に反している思います。
まとめ
最初はFragmentにtoolbarを持たせようかと思っていましたが、茨の道っぽいのでやめました。
setSupportActionBarを呼ばないならtoolbarを使うメリットはほとんどありません。
toolbarはactivityで管理して、toolbarに表示するMenuはFragmentで管理することで目的は達成できました
この記事が気に入ったらサポートをしてみませんか?