メニューを追加する

Compose を試す
Jetpack Compose は Android で推奨される UI ツールキットです。Compose でコンポーネントを追加する方法を学習します。

メニューは、さまざまなタイプのアプリで共通のユーザー インターフェース コンポーネントです。なじみのある一貫性のあるユーザー エクスペリエンスを提供するには、Menu API を使用して、アクティビティ内にユーザー アクションやその他のオプションを提示します。

オーバーフロー メニューの例を示す画像
図 1.アイコンのタップによってトリガーされるメニュー。オーバーフロー メニュー アイコンの下に表示されます。

このドキュメントでは、すべてのバージョンの Android で、3 つの基本的なタイプのメニューまたはアクション プレゼンテーションを作成する方法について説明します。

オプション メニューとアプリバー
オプション メニューは、アクティビティのメニュー項目をまとめたものです。検索、メールの作成、設定など、アプリにグローバルに影響するアクションを配置します。

オプション メニューの作成のセクションをご覧ください。

コンテキスト メニューとコンテキスト アクション モード
コンテキスト メニューは、ユーザーが要素を長押しすると表示されるフローティング メニューです。選択したコンテンツやコンテキスト フレームに影響するアクションを提供します。

コンテキスト アクション モードでは、選択したコンテンツに影響するアクション アイテムが画面上部のバーに表示され、ユーザーは複数のアイテムを選択できます。

コンテキスト メニューを作成するをご覧ください。

ポップアップ メニュー
ポップアップ メニューには、メニューを呼び出すビューに固定された項目のリストが縦方向に表示されます。これは、特定のコンテンツに関連するアクションをオーバーフローさせる場合や、コマンドの 2 番目の部分にオプションを提供する場合に適しています。ポップアップ メニューのアクションは、対応するコンテンツに直接影響しません。そのため、コンテキスト アクションがあります。ポップアップ メニューは、アクティビティ内のコンテンツ領域に関連する拡張アクション用です。

ポップアップ メニューを作成するのセクションをご覧ください。

XML でメニューを定義する

Android では、すべてのメニュータイプについて、メニュー項目を定義する標準 XML 形式が用意されています。アクティビティのコードでメニューを作成する代わりに、メニューとそのすべてのアイテムを XML メニュー リソースで定義します。その後、アクティビティまたはフラグメントでメニュー リソースをインフレート(Menu オブジェクトとして読み込む)できます。

メニュー リソースの使用が推奨される理由は次のとおりです。

  • XML でメニュー構造の視覚化が簡単になる。
  • メニューのコンテンツをアプリの動作コードと分離します。
  • アプリリソース フレームワークを利用して、プラットフォームのバージョン、画面サイズ、その他の構成ごとに代替メニュー構成を作成できます。

メニューを定義するには、プロジェクトの res/menu/ ディレクトリ内に XML ファイルを作成し、次の要素を使用してメニューをビルドします。

<menu>
メニュー項目のコンテナである Menu を定義します。<menu> 要素はファイルのルートノードである必要があり、1 つ以上の <item> 要素と <group> 要素を保持できます。
<item>
メニュー内の 1 つのアイテムを表す MenuItem を作成します。この要素には、サブメニューを作成するためにネストされた <menu> 要素を含めることができます。
<group>
<item> 要素用の非表示のコンテナ(省略可)。メニュー項目を分類し、アクティブ状態や公開設定などのプロパティを共有できるようにします。詳細については、メニュー グループを作成するをご覧ください。

game_menu.xml という名前のメニューの例を次に示します。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game"
          app:showAsAction="ifRoom"/>
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

<item> 要素では、アイテムの外観と動作を定義するために使用できる複数の属性がサポートされています。上のメニューの項目には、次の属性が含まれます。

android:id
アイテムに固有のリソース ID。これにより、ユーザーがアイテムを選択すると、アプリがそのアイテムを認識できるようになります。
android:icon
アイテムのアイコンとして使用するドローアブルへの参照。
android:title
アイテムのタイトルとして使用する文字列への参照。
android:showAsAction
このアイテムがアプリバーにアクション アイテムとして表示されるタイミングと方法を指定します。

これらは使用する最も重要な属性ですが、他にも多くの属性があります。サポートされているすべての属性については、メニュー リソースのドキュメントをご覧ください。

任意のメニューの項目にサブメニューを追加するには、<menu> 要素を <item> の子として追加します。サブメニューは、PC アプリのメニューバーにあるアイテム(ファイル編集表示など)のように、トピックに整理できる多くの機能がある場合に便利です。次の例をご覧ください。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:title="@string/file" >
        <!-- "file" submenu -->
        <menu>
            <item android:id="@+id/create_new"
                  android:title="@string/create_new" />
            <item android:id="@+id/open"
                  android:title="@string/open" />
        </menu>
    </item>
</menu>

アクティビティでメニューを使用するには、メニュー リソースをインフレートし、MenuInflater.inflate() を使用して XML リソースをプログラム可能なオブジェクトに変換します。以下のセクションでは、メニュータイプごとにメニューをインフレートする方法について説明します。

オプション メニューの作成

図 1 のようなオプション メニューには、現在のアクティビティ コンテキストに関連するアクションやその他のオプション([検索]、[メールを作成]、[設定] など)が含まれます。

Google スプレッドシート アプリのアプリバーを示す画像
図 2. アクション オーバーフロー ボタンなどの複数のボタンが表示されている Google スプレッドシート アプリ。

オプション メニューの項目は、Activity サブクラスまたは Fragment サブクラスから宣言できます。アクティビティとフラグメントの両方でオプション メニューのアイテムを宣言すると、アイテムは UI 内で結合されます。アクティビティのアイテムが最初に表示され、次に各フラグメントのアイテムが、フラグメントがアクティビティに追加された順序で表示されます。必要に応じて、移動する各 <item>android:orderInCategory 属性を使用してメニュー項目を並べ替えることができます。

アクティビティのオプション メニューを指定するには、onCreateOptionsMenu() をオーバーライドします。フラグメントには、独自の onCreateOptionsMenu() コールバックが用意されています。この方法では、XML で定義されたメニュー リソースを、コールバックで提供される Menu にインフレートできます。これを次の例に示します。

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    val inflater: MenuInflater = menuInflater
    inflater.inflate(R.menu.game_menu, menu)
    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

add() を使用してメニュー項目を追加し、findItem() を使用して項目を取得し、MenuItem API を使用してプロパティを変更することもできます。

クリック イベントを処理する

ユーザーがアプリバーのアクション アイテムを含め、オプション メニューから項目を選択すると、アクティビティの onOptionsItemSelected() メソッドが呼び出されます。このメソッドでは、選択された MenuItem が渡されます。アイテムを識別するには、getItemId() を呼び出します。これは、メニュー リソースの android:id 属性で定義されたメニュー アイテムの一意の ID を返すか、add() メソッドに整数を指定して返します。この ID を既知のメニュー項目と照合して、適切なアクションを実行できます。

Kotlin

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)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection.
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

メニュー項目を正常に処理する場合、true を返します。メニュー項目を処理しない場合は、onOptionsItemSelected() のスーパークラス実装を呼び出します。デフォルトの実装では false が返されます。

アクティビティにフラグメントが含まれている場合、システムはまずアクティビティに対して onOptionsItemSelected() を呼び出します。その後、true が返されるか、すべてのフラグメントが呼び出されるまで、フラグメントが追加された順に各フラグメントが追加されます。

実行時にメニュー項目を変更する

システムが onCreateOptionsMenu() を呼び出した後は、ユーザーが入力した Menu のインスタンスが保持され、メニューが無効になっていない限り、onCreateOptionsMenu() が再度呼び出されることはありません。ただし、onCreateOptionsMenu() は初期のメニュー状態を作成し、アクティビティのライフサイクル中に変更しない場合にのみ使用します。

アクティビティのライフサイクル中に発生するイベントに基づいてオプション メニューを変更する場合は、onPrepareOptionsMenu() メソッドで行います。このメソッドは、現在存在する Menu オブジェクトを渡すため、アイテムの追加、削除、無効化などによりオブジェクトを変更できます。フラグメントは onPrepareOptionsMenu() コールバックも備えています。

メニュー項目がアプリバーに表示されている場合、オプション メニューは常に開いていると見なされます。イベント発生時にメニューの更新を実行したい場合は、invalidateOptionsMenu() を呼び出して、onPrepareOptionsMenu() を呼び出すようにシステムにリクエストします。

コンテキスト メニューを作成する

フローティング コンテキスト メニューを示す画像
図 3. フローティング コンテキスト メニュー

コンテキスト メニューには、UI の特定のアイテムやコンテキスト フレームに影響するアクションが表示されます。どのビューにもコンテキスト メニューを提供できますが、ほとんどの場合は、各アイテムに対してユーザーが直接アクションを実行できる RecylerView などのビュー コレクション内のアイテムに使用されます。

コンテキスト アクションを提供するには、次の 2 つの方法があります。

  • フローティング コンテキスト メニュー。メニューは、コンテキスト メニューのサポートを宣言するビューでユーザーが長押しすると、ダイアログと同様に、メニュー項目のフローティング リストとして表示されます。ユーザーは一度に 1 つのアイテムに対してコンテキスト アクションを実行できます。
  • コンテキスト アクション モード。このモードは ActionMode のシステム実装であり、コンテキスト アクションバー(CAB)を画面の上部に、選択したアイテムに影響するアクション アイテムとともに表示します。このモードがアクティブの場合、ユーザーは複数のアイテムに対して一度にアクションを実行できます(アプリがサポートしている場合)。

フローティング コンテキスト メニューを作成する

フローティング コンテキスト メニューを表示する方法は次のとおりです。

  1. registerForContextMenu() を呼び出して View を渡すことで、コンテキスト メニューが関連付けられている View を登録します。

    アクティビティで RecyclerView を使用していて、各アイテムに同じコンテキスト メニューを表示させたい場合は、RecyclerViewregisterForContextMenu() に渡してコンテキスト メニューにすべてのアイテムを登録します。

  2. Activity または FragmentonCreateContextMenu() メソッドを実装します。

    登録済みのビューが長押しイベントを受信すると、onCreateContextMenu() メソッドが呼び出されます。ここでは、次の例のように、通常はメニュー リソースをインフレートして、メニュー項目を定義します。

    Kotlin

        override fun onCreateContextMenu(menu: ContextMenu, v: View,
                                menuInfo: ContextMenu.ContextMenuInfo) {
            super.onCreateContextMenu(menu, v, menuInfo)
            val inflater: MenuInflater = menuInflater
            inflater.inflate(R.menu.context_menu, menu)
        }
        

    Java

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v,
                                        ContextMenuInfo menuInfo) {
            super.onCreateContextMenu(menu, v, menuInfo);
            MenuInflater inflater = getMenuInflater();
            inflater.inflate(R.menu.context_menu, menu);
        }
        

    MenuInflater を使用すると、メニュー リソースからコンテキスト メニューをインフレートできます。このコールバック メソッドのパラメータには、ユーザーが選択する View と、選択したアイテムに関する追加情報を提供する ContextMenu.ContextMenuInfo オブジェクトが含まれます。アクティビティに、それぞれ異なるコンテキスト メニューを提供する複数のビューがある場合、これらのパラメータを使用して、インフレートするコンテキスト メニューを決定できます。

  3. 次の例に示すように、onContextItemSelected() を実装します。ユーザーがメニュー項目を選択すると、システムがこのメソッドを呼び出して、適切なアクションを実行できるようにします。

    Kotlin

        override fun onContextItemSelected(item: MenuItem): Boolean {
            val info = item.menuInfo as AdapterView.AdapterContextMenuInfo
            return when (item.itemId) {
                R.id.edit -> {
                    editNote(info.id)
                    true
                }
                R.id.delete -> {
                    deleteNote(info.id)
                    true
                }
                else -> super.onContextItemSelected(item)
            }
        }
        

    Java

        @Override
        public boolean onContextItemSelected(MenuItem item) {
            AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
            switch (item.getItemId()) {
                case R.id.edit:
                    editNote(info.id);
                    return true;
                case R.id.delete:
                    deleteNote(info.id);
                    return true;
                default:
                    return super.onContextItemSelected(item);
            }
        }
        

    getItemId() メソッドは、選択されたメニュー項目の ID を照会します。この ID は、XML でメニューを定義するに示すように、android:id 属性を使用して XML で各メニュー項目に割り当てます。

    メニュー項目を正常に処理する場合、true を返します。メニュー項目を処理しない場合は、メニュー項目をスーパークラスの実装に渡します。アクティビティにフラグメントが含まれている場合、アクティビティはまずこのコールバックを受け取ります。未処理のときにスーパークラスを呼び出すと、true または false が返されるまで、各フラグメントの追加順にイベントを各フラグメントのそれぞれのコールバック メソッドに 1 つずつ渡します。Activityandroid.app.Fragment のデフォルト実装では false が返されるため、未処理のときは常にスーパークラスを呼び出します。

コンテキスト アクション モードを使用する

コンテキスト アクション モードは ActionMode のシステム実装であり、ユーザーによるコンテキスト アクションの実行に重点を置いています。ユーザーがアイテムを選択してこのモードを有効にすると、コンテキスト アクションバーが画面の上部に表示され、選択したアイテムに対してユーザーが実行できるアクションが表示されます。このモードが有効になっている場合、ユーザーは複数のアイテムを選択でき(アプリがサポートしている場合)、アイテムの選択を解除してアクティビティ内を移動できます。ユーザーがすべてのアイテムの選択を解除したり、[戻る] ボタンをタップしたり、バーの左側にある [完了] アクションをタップしたりすると、アクション モードは無効になり、コンテキスト アクションバーは表示されなくなります。

コンテキスト アクションを提供するビューの場合、通常、次の 2 つのイベントのいずれかまたは両方が発生したときに、コンテキスト アクション モードを呼び出します。

  • ユーザーがビューを長押しします。
  • ユーザーがチェックボックスまたは類似の UI コンポーネントをビュー内で選択する。

アプリでコンテキスト アクション モードを呼び出し、各アクションの動作を定義する方法は、設計によって異なります。デザインには次の 2 種類があります。

  • 個別の任意のビューでのコンテキスト アクション用。
  • RecyclerView 内のアイテムのグループに対するコンテキスト アクションのバッチ アクションの場合、ユーザーは複数のアイテムを選択して、そのすべてに対してアクションを実行できます。

次のセクションでは、各シナリオに必要な設定について説明します。

個々のビューでコンテキスト アクション モードを有効にする

ユーザーが特定のビューを選択した場合にのみコンテキスト アクション モードを呼び出すには、次のようにします。

  1. 次の例に示すように、ActionMode.Callback インターフェースを実装します。そのコールバック メソッドでは、コンテキスト アクションバーのアクションの指定、アクション アイテムでのクリック イベントへの応答、アクション モードのその他のライフサイクル イベントの処理を行うことができます。

    Kotlin

        private val actionModeCallback = object : ActionMode.Callback {
            // Called when the action mode is created. startActionMode() is called.
            override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
                // Inflate a menu resource providing context menu items.
                val inflater: MenuInflater = mode.menuInflater
                inflater.inflate(R.menu.context_menu, menu)
                return true
            }
    
            // Called each time the action mode is shown. Always called after
            // onCreateActionMode, and might be called multiple times if the mode
            // is invalidated.
            override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
                return false // Return false if nothing is done
            }
    
            // Called when the user selects a contextual menu item.
            override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
                return when (item.itemId) {
                    R.id.menu_share -> {
                        shareCurrentItem()
                        mode.finish() // Action picked, so close the CAB.
                        true
                    }
                    else -> false
                }
            }
    
            // Called when the user exits the action mode.
            override fun onDestroyActionMode(mode: ActionMode) {
                actionMode = null
            }
        }
        

    Java

        private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
    
            // Called when the action mode is created. startActionMode() is called.
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                // Inflate a menu resource providing context menu items.
                MenuInflater inflater = mode.getMenuInflater();
                inflater.inflate(R.menu.context_menu, menu);
                return true;
            }
    
            // Called each time the action mode is shown. Always called after
            // onCreateActionMode, and might be called multiple times if the mode
            // is invalidated.
            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                return false; // Return false if nothing is done.
            }
    
            // Called when the user selects a contextual menu item.
            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
               switch (item.getItemId()) {
                    case R.id.menu_share:
                        shareCurrentItem();
                        mode.finish(); // Action picked, so close the CAB.
                        return true;
                    default:
                        return false;
                }
            }
    
            // Called when the user exits the action mode.
            @Override
            public void onDestroyActionMode(ActionMode mode) {
                actionMode = null;
            }
        };
        

    これらのイベント コールバックは、オプション メニューのコールバックとほぼ同じですが、それぞれがイベントに関連付けられた ActionMode オブジェクトを渡す点が異なります。ActionMode API を使用すると、setTitle()setSubtitle() でタイトルとサブタイトルを変更するなど、CAB にさまざまな変更を加えることができます。これは、選択されたアイテム数を示すのに便利です。

    上記のサンプルでは、アクション モードが破棄されたときに actionMode 変数を null に設定します。次のステップでは、初期化の方法と、アクティビティやフラグメントにメンバー変数を保存することがどのように役立つかを確認します。

  2. ユーザーがビューを長押ししたときなど、バーを表示するときに startActionMode() を呼び出します。

    Kotlin

        someView.setOnLongClickListener { view ->
            // Called when the user performs a touch & hold on someView.
            when (actionMode) {
                null -> {
                    // Start the CAB using the ActionMode.Callback defined earlier.
                    actionMode = activity?.startActionMode(actionModeCallback)
                    view.isSelected = true
                    true
                }
                else -> false
            }
        }
        

    Java

        someView.setOnLongClickListener(new View.OnLongClickListener() {
            // Called when the user performs a touch & hold on someView.
            public boolean onLongClick(View view) {
                if (actionMode != null) {
                    return false;
                }
    
                // Start the CAB using the ActionMode.Callback defined earlier.
                actionMode = getActivity().startActionMode(actionModeCallback);
                view.setSelected(true);
                return true;
            }
        });
        

    startActionMode() を呼び出すと、作成された ActionMode が返されます。これをメンバー変数に保存することで、他のイベントに応じてコンテキスト アクションバーを変更できます。 上記のサンプルでは、アクション モードを開始する前にメンバーが null かどうかをチェックすることで、ActionMode インスタンスがすでにアクティブな場合に再作成されないように ActionMode を使用しています。

ポップアップ メニューを作成する

右上のオーバーフロー ボタンに固定された Gmail アプリのポップアップ メニューを示す画像。
図 4. 右上のオーバーフロー ボタンに固定された Gmail アプリのポップアップ メニュー。

PopupMenu は、View に固定されたモーダル メニューです。スペースがある場合はアンカービューの下、スペースがない場合はビューの上に表示されます。次の場合に役立ちます。

  • 図 4 に示すように、Gmail のメールヘッダーなど、特定のコンテンツに関連するアクションにはオーバーフロー スタイルのメニューを提供します。
  • コマンド文の 2 番目の部分を提供する(さまざまな [Add] オプションを含むポップアップ メニューを生成する [Add] とマークされたボタンなど)。
  • 永続的な選択を保持しない Spinner と同様のメニューを提供する。

XML でメニューを定義している場合は、次の方法でポップアップ メニューを表示できます。

  1. コンストラクタを使用して PopupMenu をインスタンス化します。これにより、現在のアプリの Context と、メニューが固定されている View を受け取ります。
  2. MenuInflater を使用して、PopupMenu.getMenu() から返される Menu オブジェクトにメニュー リソースをインフレートします。
  3. PopupMenu.show() を呼び出します。

たとえば、ポップアップ メニューを表示するボタンは次のとおりです。

<ImageButton
    android:id="@+id/dropdown_menu"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/descr_overflow_button"
    android:src="@drawable/arrow_drop_down" />

アクティビティでは、次のようにポップアップ メニューが表示されます。

Kotlin

findViewById<ImageButton>(R.id.dropdown_menu).setOnClickListener {
    val popup = PopupMenu(this, it)
    val inflater: MenuInflater = popup.menuInflater
    inflater.inflate(R.menu.actions, popup.menu)
    popup.show()
}

Java

findViewById(R.id.dropdown_menu).setOnClickListener(v -> {
    PopupMenu popup = new PopupMenu(this, v);
    popup.getMenuInflater().inflate(R.menu.actions, popup.getMenu());
    popup.show();
});

ユーザーがアイテムを選択するか、メニュー領域の外側をタップすると、メニューが閉じます。消去イベントをリッスンするには、PopupMenu.OnDismissListener を使用します。

クリック イベントを処理する

ユーザーがメニュー項目を選択したときにアクションを実行するには、PopupMenu.OnMenuItemClickListener インターフェースを実装し、setOnMenuItemclickListener() を呼び出して PopupMenu に登録します。ユーザーがアイテムを選択すると、インターフェース内で onMenuItemClick() コールバックが呼び出されます。

これを次の例に示します。

Kotlin

fun showMenu(v: View) {
    PopupMenu(this, v).apply {
        // MainActivity implements OnMenuItemClickListener.
        setOnMenuItemClickListener(this@MainActivity)
        inflate(R.menu.actions)
        show()
    }
}

override fun onMenuItemClick(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.archive -> {
            archive(item)
            true
        }
        R.id.delete -> {
            delete(item)
            true
        }
        else -> false
    }
}

Java

public void showMenu(View v) {
    PopupMenu popup = new PopupMenu(this, v);

    // This activity implements OnMenuItemClickListener.
    popup.setOnMenuItemClickListener(this);
    popup.inflate(R.menu.actions);
    popup.show();
}

@Override
public boolean onMenuItemClick(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.archive:
            archive(item);
            return true;
        case R.id.delete:
            delete(item);
            return true;
        default:
            return false;
    }
}

メニュー グループを作成する

メニュー グループは、特定の特徴を共有するメニュー項目のコレクションです。グループを使用すると、次のことができます。

  • setGroupVisible() を使用して、すべてのアイテムの表示と非表示を切り替えます。
  • setGroupEnabled() を使用してすべてのアイテムを有効または無効にします。
  • setGroupCheckable() を使用して、すべての項目をオンに可能にするかどうかを指定します。

グループを作成するには、メニュー リソースの <group> 要素内に <item> 要素をネストするか、add() メソッドでグループ ID を指定します。

グループを含むメニュー リソースの例を次に示します。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_save"
          android:icon="@drawable/menu_save"
          android:title="@string/menu_save" />
    <!-- menu group -->
    <group android:id="@+id/group_delete">
        <item android:id="@+id/menu_archive"
              android:title="@string/menu_archive" />
        <item android:id="@+id/menu_delete"
              android:title="@string/menu_delete" />
    </group>
</menu>

グループ内の項目は最初の項目と同じレベルに表示されます。メニューの 3 つの項目はすべて兄弟です。ただし、グループ ID を参照して上記のメソッドを使用することで、グループ内の 2 つのアイテムのトレイトを変更できます。また、グループ化されたアイテムが分割されることはありません。たとえば、各アイテムに対して android:showAsAction="ifRoom" を宣言すると、両方がアクションバーに表示されるか、両方がアクション オーバーフローに表示されます。

オンにできるメニュー項目を使用する

図 5.オンにできるアイテムがあるサブメニュー

メニューは、スタンドアロン オプションのチェックボックスや、相互に排他的なオプション グループのラジオボタンを使用して、オプションのオンとオフを切り替えるためのインターフェースとして使用できます。図 5 は、ラジオボタンでオンにできる項目を含むサブメニューを示しています。

オンにできる動作は、<item> 要素の android:checkable 属性を使用して個々のメニュー項目に、または <group> 要素の android:checkableBehavior 属性を使用してグループ全体に対して定義できます。たとえば、このメニュー グループのすべての項目はラジオボタンでオンにできます。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item android:id="@+id/red"
              android:title="@string/red" />
        <item android:id="@+id/blue"
              android:title="@string/blue" />
    </group>
</menu>

android:checkableBehavior 属性には次のいずれかを指定できます。

single
グループ内の 1 つの項目のみをオンにできる(ラジオボタン)。
all
すべての項目をオンにできる(チェックボックスがオン)。
none
オンにできるアイテムはありません。

<item> 要素の android:checked 属性を使用してアイテムにデフォルトのチェック状態を適用し、setChecked() メソッドを使用してコード内でその状態を変更できます。

チェック可能なアイテムが選択されると、それぞれのアイテムで選択されたコールバック メソッド(onOptionsItemSelected() など)が呼び出されます。チェックボックスやラジオボタンは状態を自動的には変更しないため、ここでチェックボックスの状態を設定します。isChecked() を使用してアイテムの現在の状態(ユーザーが選択する前の状態)をクエリし、setChecked() を使用してチェック状態を設定できます。これを次の例に示します。

Kotlin

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.vibrate, R.id.dont_vibrate -> {
            item.isChecked = !item.isChecked
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Java

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.vibrate:
        case R.id.dont_vibrate:
            if (item.isChecked()) item.setChecked(false);
            else item.setChecked(true);
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

この方法でオンにされた状態を設定しない場合、ユーザーが選択したチェックボックスやラジオボタンの表示状態は変わりません。状態を設定すると、アクティビティはアイテムのチェック状態を保持するため、ユーザーが後でメニューを開いたときに、設定したチェック状態が表示されます。

インテントに基づいてメニュー項目を追加する

メニュー項目が Intent を使用してアクティビティを起動したい場合もあります。これは、アプリ内のアクティビティでも別のアプリのアクティビティでもかまいません。使用するインテントがわかっていて、そのインテントを開始する特定のメニュー項目がある場合は、onOptionsItemSelected() コールバックなどの適切な on-item-selected コールバック メソッド中に、startActivity() を使用してインテントを実行できます。

ただし、ユーザーのデバイスにインテントを処理するアプリが含まれているかどうか確信が持てない場合は、そのインテントを呼び出すメニュー項目を追加すると、インテントがアクティビティに解決されないため、メニュー項目が機能しなくなる可能性があります。この問題を解決するため、Android では、インテントを処理するデバイス上で Android がアクティビティを検出したときに、メニュー項目を動的にメニューに追加できます。

インテントを受け入れる使用可能なアクティビティに基づいてメニュー項目を追加するには、次の操作を行います。

  1. カテゴリ CATEGORY_ALTERNATIVECATEGORY_SELECTED_ALTERNATIVE のいずれか、または両方と、その他の要件を使用してインテントを定義します。
  2. Menu.addIntentOptions() を呼び出します。次に、Android はインテントを実行できるアプリを検索し、メニューに追加します。

インテントを満たすアプリがインストールされていない場合、メニュー項目は追加されません。

これを次の例に示します。

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)

    // Create an Intent that describes the requirements to fulfill, to be
    // included in the menu. The offering app must include a category value
    // of Intent.CATEGORY_ALTERNATIVE.
    val intent = Intent(null, dataUri).apply {
        addCategory(Intent.CATEGORY_ALTERNATIVE)
    }

    // Search and populate the menu with acceptable offering apps.
    menu.addIntentOptions(
            R.id.intent_group,  // Menu group to which new items are added.
            0,                  // Unique item ID (none).
            0,                  // Order for the items (none).
            this.componentName, // The current activity name.
            null,               // Specific items to place first (none).
            intent,             // Intent created above that describes the requirements.
            0,                  // Additional flags to control items (none).
            null)               // Array of MenuItems that correlate to specific items (none).

    return true
}

Java

@Override
public boolean onCreateOptionsMenu(Menu menu){
    super.onCreateOptionsMenu(menu);

    // Create an Intent that describes the requirements to fulfill, to be
    // included in the menu. The offering app must include a category value
    // of Intent.CATEGORY_ALTERNATIVE.
    Intent intent = new Intent(null, dataUri);
    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);

    // Search and populate the menu with acceptable offering apps.
    menu.addIntentOptions(
         R.id.intent_group,         // Menu group to which new items are added.
         0,                         // Unique item ID (none).
         0,                         // Order for the items (none).
         this.getComponentName(),   // The current activity name.
         null,                      // Specific items to place first (none).
         intent,                    // Intent created above that describes the requirements.
         0,                         // Additional flags to control items (none).
         null);                     // Array of MenuItems that correlate to specific items (none).

    return true;
}

定義されたインテントに一致するインテント フィルタを提供するアクティビティごとに、インテント フィルタの android:label の値をメニュー項目のタイトルに、アプリアイコンをメニュー項目のアイコンとして使用して、メニュー項目が追加されます。addIntentOptions() メソッドは、追加されたメニュー項目の数を返します。

アクティビティを他のメニューに追加できるようにします

アクティビティのサービスを他のアプリに提供することで、前述のロールを逆にして他のアプリのメニューに自分のアプリを含めることができます。

他のアプリのメニューに含めるには、通常どおりインテント フィルタを定義しますが、インテント フィルタ カテゴリには、CATEGORY_ALTERNATIVE 値または CATEGORY_SELECTED_ALTERNATIVE 値、あるいはその両方を指定します。これを次の例に示します。

<intent-filter label="@string/resize_image">
    ...
    <category android:name="android.intent.category.ALTERNATIVE" />
    <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    ...
</intent-filter>

インテント フィルタの作成方法については、インテントとインテント フィルタをご覧ください。