メニューを追加する

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>
メニュー内の単一の項目を表す 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 アプリのメニューバーのアイテム(FileEditView など)のように、トピック別に整理できる多くの機能がある場合に便利です。次の例をご覧ください。

<?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 属性または add() メソッドに指定された整数で、メニュー アイテムの一意の ID を返します。この 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 は、android:id 属性を使用して XML で各メニュー項目に割り当てます(XML でメニューを定義するを参照)。

    メニュー項目を正常に処理する場合、true を返します。メニュー項目を処理しない場合は、メニュー項目をスーパークラスの実装に渡します。アクティビティにフラグメントが含まれている場合、アクティビティは最初にこのコールバックを受け取ります。未処理の状態でスーパークラスを呼び出すと、true または false が返されるまで、各フラグメントが追加された順番に各フラグメントのそれぞれのコールバック メソッドにイベントが渡されます。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 が返されます。これをメンバー変数に保存することで、他のイベントに応じてコンテキスト アクションバーを変更できます。上記のサンプルでは、ActionMode を使用して、アクション モードを開始する前にメンバーが null かどうかを確認することで、ActionMode インスタンスがすでにアクティブな場合に再作成されないようにします。

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

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

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

  • 図 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_ALTERNATIVE カテゴリ、CATEGORY_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>

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