ActionBarをFragmentに対応させる

# ActionBarをMenuHostHelperに対応させる

私の過去記事でActcionBarのサンプルを投稿しましたが、Activityにか対応していませんでした。
[ActionBarをカスタマイズしてみる](https://qiita.com/cozyk100/items/8aa1c622f3437e73e46b)

Fragmentに対応させるのと当時に、ActcionBarの制御方法がMenuHostHelperに変わっているので、その対応も同時に紹介します。

MenuHostHelperについては公式でもあまり詳しく説明されておらず、[androidx.activity:activity:1.4.0-alpha01の変更点](https://developer.android.com/jetpack/androidx/releases/activity?hl=ja#1.4.0-alpha01)として説明されています。

そして、今は公式ではActionBarよりも[ToolBar](https://developer.android.com/training/appbar?hl=ja)を使用することを推奨していて、説明もToolbarに変わっています。**ToolBarの説明は別途として**、今回は従来通りのActionBarをMenuHostHelperに対応させる説明をします。

## MainActivity
メニューの定義ファイルの作り方は前回と同じです。MainActivity.kt側の対応は、以下の様になります。わかりやすいように関数を分けました。
```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater) .apply {
            setContentView(this.root)
        }
        supportActionBar?.setTitle("あー、ほげほげ")
        supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.GREEN))
        setupMenuBar()
    }

    private fun setupMenuBar() {
            addMenuProvider(object : MenuProvider {
            override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
                menuInflater.inflate(R.menu.menu_sample, menu)
            }

            override fun onMenuItemSelected(item: MenuItem): Boolean {
                when (item.itemId) {
                    R.id.iconItem1 ->  ・・・                    
                    else -> {}
                }
                return true
            }
        })
    }
}
```
ミソは
```kotlin
addMenuProvider(object : MenuProvider { ・・・
```
でこのaddMenuProviderはComponentActivityの中で、[MenuHostHelper#addMenuProvider](https://developer.android.com/reference/kotlin/androidx/core/view/MenuHostHelper#addMenuProvider(androidx.core.view.MenuProvider,androidx.lifecycle.LifecycleOwner))を呼び出しています。

関数、[onCreateMenu](https://developer.android.com/reference/kotlin/androidx/core/view/MenuHostHelper#onCreateMenu(android.view.Menu,android.view.MenuInflater))inflateして、[onMenuItemSelected](https://developer.android.com/reference/kotlin/androidx/core/view/MenuHostHelper#onMenuItemSelected(android.view.MenuItem))でActionBarのアイコン、またはメニューがタップされた場合の処理を書きます。

## Fragment側の対応
おそらく、Activity1個に対し複数Fragmnent方式でくるくる画面を入れ替えて遷移するような方式だとActionBarは全てのFragmnentで共有したくなると思います。一部、特定のFragmentによってはActionBarの特定のアイコン、メニューを非表示にしたくなると思います。（タップさせない）

その場合、最大公約数的に、メニュー定義ファイルは1個で全てを記述し、MainActivityに処理を集約します。各Fragmentは違うところだけ書きます。

```kotlin:Fragment1.kt
class Fragment1 : Fragment() {
    private lateinit var binding: Fragment1Binding
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View {
        binding = Fragment1Binding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setupMenuBar()
        ・・・
    }

    private fun setupMenuBar() {
         val menuHost: MenuHost = requireActivity()
         menuHost.addMenuProvider(object : MenuProvider {
            override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
                // 空
            }

             override fun onPrepareMenu(menu: Menu) {
                 menu.findItem(R.id.iconItem1).isVisible = false // アイコン
                 menu.findItem(R.id.menu_item3_1).isVisible = false // メニュー
             }

            override fun onMenuItemSelected(item: MenuItem): Boolean {
                // 空
                return true
            }
        }, viewLifecycleOwner, Lifecycle.State.RESUMED)
    }
}
```
わかりやすいように関数を分けました。Activityの場合とちょっと違います。
```
val menuHost: MenuHost = requireActivity()
```
MenuHostはActivityのMenuHostを取得しています。[addMenuProvider](https://developer.android.com/reference/kotlin/androidx/core/view/MenuHostHelper#addMenuProvider(androidx.core.view.MenuProvider,androidx.lifecycle.LifecycleOwner,androidx.lifecycle.Lifecycle.State))はActivityと引数が違います。LifecycleOwnerと、Lifecycle.Stateが必要です。
```kotlin
fun addMenuProvider(
    provider: MenuProvider,
    owner: LifecycleOwner,
    state: Lifecycle.State
): Unit
```
onCreateMenu関数は空です。Activityではここでメニュー定義ファイルをinflateしていましたが、FragmentでもinflateするとActionBarのアイコン、メニューが2倍になります。

onMenuItemSelected関数も空でtrueだけ返せばいいです。ActionBarのアイコン、メニューがタップされた場合のハンドリングは全てMainActivityでやります。

あと、MainActivityになかったのが、onPrepareMenu関数。
ここではこのFragmentに特化して表示したくない、ActionBarのアイコン、メニューがある場合、そのisVisible を false にします。

Fragmentが他に複数ある場合も同様です。

## 最後に
ソースは[gitHub](https://github.com/cozyk100/AndroidStudioProjectsPublic/tree/main/ActionBarKotlin)にpushしました。