Navigation ComponentでFragmentからメニューを表示する場合。

メニューの古い作りかた

Navigation Component使用時にFragmentでApp Barのメニューを作るには以下の手順で実装していた。

メニューリソースの作成

<menu 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"
    tools:context="com.example.myapplication.MainActivity">
    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="@string/action_settings"
        app:showAsAction="never" />
</menu>

onCreateでsetOnOptionsMenu(true)を呼ぶ

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

onCreateOptionsMenuメソッドをオーバライドしてメニューをinflateする

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    super.onCreateOptionsMenu(menu, inflater)
    inflater.inflate(R.menu.menu_main, menu)
}

onOptionsItemSelectedメソッドをオーバライドしてメニュー選択時の処理を実装する

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.action_settings -> {
            Log.d("test", "Settingがクリックされました")
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

上記手順はdeprecatedになった

FragmentクラスのsetHasOptionsMenu, onCreateOptionsMenu, onOptionsItemSelectedメソッドがdeprecatedとなり、 代わりにMenuProviderを登録することで代替することになった。

実装

ActivityaddMenuProviderを呼び出してMenuProviderを登録する。

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    _binding = FragmentFirstBinding.inflate(inflater, container, false)


    activity?.addMenuProvider(
        object : MenuProvider {
            override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
                inflater.inflate(R.menu.menu_main, menu)
            }

            override fun onMenuItemSelected(item: MenuItem): Boolean {
                return when (item.itemId) {
                    R.id.action_settings -> {
                        Log.d("test", "Settingがクリックされました")
                        true
                    }
                    else -> true
                }
            }
        },
        viewLifecycleOwner,
        Lifecycle.State.RESUMED
    )

    return binding.root

}

対応関係

以下のように置き換えられる。

  • onCreateOptionsMenu()MenuProvideronCreateMenuの実装
  • onOptionsItemSelectedMenuProvideronMenuItemSelectedの実装
  • setOnOptionsMenu(true)activity?.addMenuProviderMenuProviderを登録

注意点

Navigation ComponentでFragmentからaddMenuProviderを呼ぶときは、addMenuProvider()の第2・第3引数を忘れないようにする。(viewLifecycleOwner, Lifecycle.State.RESUMED)

これはこのフラグメントのライフサイクルに追従させる設定。
忘れると親Activityのライフサイクルに追従するので別の画面に遷移してもメニューが残ってしまう。