page.title=メニュー parent.title=ユーザー インターフェース parent.link=index.html @jd:body
メニューは、さまざまなタイプのアプリケーションで共通するユーザー インターフェースです。使い慣れた一貫した操作感を提供するには、{@link android.view.Menu} API を使ってアクティビティでユーザーのアクションとその他のオプションを表示する必要があります。
Android 3.0(API レベル 11)からは、Android 搭載端末では専用の Menu ボタンを表示する必要はなくなりました。 この変更により、Android アプリでは従来の 6 アイテムのメニューパネルの依存関係から離れて、共通のユーザー アクションを表示するアクションバーを提供する必要があります。
一部のメニュー アイテムのデザインと操作感は変わりましたが、一連のアクションとオプションを定義する意味論は、引き続き {@link android.view.Menu} API に基づきます。 このガイドでは、すべてのバージョンの Android で表示されるメニューやアクションの基本的な 3 タイプを作成する方法について説明します。
Android 2.3 以前のバージョン向けに開発している場合は、ユーザーは Menu ボタンを押してオプション メニューパネルを表示できます。
Android 3.0 以降の場合、オプション メニューのアイテムは、画面上のアクション アイテムとオーバーフロー オプションの組み合わせでアクションバーに表示されます。 Android 3.0 からは、Menu ボタンが廃止されたため(一部の端末にはこのボタンがありません)、アクションバーを使ってアクションや他のオプションにアクセスできるよう移行する必要があります。
オプション メニューの作成のセクションをご覧ください。
Android 3.0 以降向けに開発している場合は、コンテキスト アクション モードを使って選択されたコンテンツでのアクションを有効にする必要があります。このモードでは、画面最上部にあるバーで選択されたコンテンツに影響するアクション アイテムが表示され、ユーザーは複数のアイテムを選択できます。
コンテキスト メニューの作成のセクションをご覧ください。
ポップアップ メニューの作成のセクションをご覧ください。
Android では、すべてのメニュータイプに、メニュー アイテムを定義するための標準の XML 形式が提供されます。 アクティビティのコードでメニューをビルドするのではなく、メニューとそのすべてのアイテムを XML メニュー リソースで定義してください。 その際、アクティビティやフラグメントでメニュー リソースをインフレートできます({@link android.view.Menu} オブジェクトとして読み込む)。
メニュー リソースを使うことは、次のような理由で優れた方法と言えます。
メニューを定義するには、プロジェクトの res/menu/
ディレクトリ内で XML ファイルを作成し、次の要素を含むメニューをビルドします。
<menu>
<menu>
要素は、ファイルのルートノードである必要があります。また、1 つ以上の <item>
と <group>
要素を持つことができます。
<item>
<menu>
要素を含めることができます。
<group>
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" android:showAsAction="ifRoom"/> <item android:id="@+id/help" android:icon="@drawable/ic_help" android:title="@string/help" /> </menu>
<item>
要素では、アイテムの概観と動作を定義するために使用できるいくつかの属性がサポートされています。
上記メニューのアイテムには、次の属性が含まれます。
これらの属性は使用する必要のある最も重要なものですが、他にもさまざまな属性があります。サポートされているすべての属性については、「Menu Resource」のドキュメントをご覧ください。
サブメニューを除くすべてのメニューで、{@code <item>} の子として {@code <menu>} 要素を追加すると、アイテムにサブメニューを追加できます。 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>
アクティビティでメニューを使うには、{@link android.view.MenuInflater#inflate(int,Menu) MenuInflater.inflate()} を使って、メニュー リソースをインフレートする(XML リソースをプログラム可能なオブジェクトに変換する)必要があります。 次のセクションでは、各メニュー アイテムのメニューをインフレートする方法を説明します。
オプション メニューでは、「検索」、「メールの作成」、「設定」のような、現在のアクティビティ コンテキストに関連するアクションとその他のオプションを含める必要があります。
オプション メニューのアイテムが画面上のどこに表示されるかは、開発対象のアプリケーションのバージョンによって異なります。
アクション アイテムと他のアクションバーの動作の詳細については、「Action Bar」のガイドをご覧ください。
注: Android 3.0 以降向けに開発していない場合でも、同様の効果のために、自分のアクションバー レイアウトをビルドできます。 アクションバー付きで以前のバージョンの Android をサポートする方法の一例については、アクションバーの互換性のサンプルをご覧ください。
{@link android.app.Activity} サブクラスや {@link android.app.Fragment} サブクラスのいずれかからオプション メニューのアイテムを宣言できます。 アクティビティとフラグメントの両方でオプション メニューのアイテムを宣言する場合、それらは UI に統合されます。まず、アクティビティのアイテムが表示され、次にアクティビティに各フラグメントが追加される順序で各フラグメントのアイテムが表示されます。 必要に応じて、移動する必要のある各 {@code <item>} で {@code android:orderInCategory} 属性を使ってメニュー アイテムの順序を並べ替えることができます。
アクティビティのオプション メニューを指定するには、{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} をオーバーライドします(フラグメントは独自の {@link android.app.Fragment#onCreateOptionsMenu onCreateOptionsMenu()} コールバックを提供)。 このメソッドでは、メニュー リソース(XML で定義)をコールバックで提供される {@link android.view.Menu} にインフレートできます。 次に例を示します。
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = {@link android.app.Activity#getMenuInflater()}; inflater.inflate(R.menu.game_menu, menu); return true; }
{@link android.view.Menu#add(int,int,int,int) add()} を使ってメニュー アイテムを追加し、{@link android.view.MenuItem} API でそのプロパティを修正するために、{@link android.view.Menu#findItem findItem()} でアイテムを取得することもできます。
Android 2.3.x 以前向けにアプリケーションを開発した場合、システムは {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を呼び出し、ユーザーが初めてそのメニューを開いたときにオプション メニューが作成されます。 Android 3.0 以降向けに開発した場合、アクティビティの開始時にシステムが {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を呼び出し、アクションバーにアイテムが表示されるようにします。
ユーザーがオプション メニューからアイテムを選択すると(アクションバーのアクション アイテムを含む)、アクティビティの {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} メソッドが呼び出されます。 このメソッドでは、選択された {@link android.view.MenuItem} が渡されます。{@link android.view.MenuItem#getItemId()} を呼び出してアイテムを識別できます。これにより、メニュー アイテムに対して一意の ID が返されます(メニュー リソースで {@code android:id} 属性を定義するか、{@link android.view.Menu#add(int,int,int,int) add()} メソッドに指定された整数で)。 この ID を既知のメニュー アイテムと突き合わせて適切なアクションを実行できます。 次に例を示します。
@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); } }
メニュー アイテムを正常に処理する場合、{@code true} を返します。メニュー アイテムを処理しない場合は、{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のスーパークラスの実装を呼び出す必要があります(デフォルトの実装では fause が返されます)。
アクティビティにフラグメントが含まれる場合は、システムはまずアクティビティに対して {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} を呼び出し、次に {@code true} が返されるまで、またはすべてのフラグメントが呼び出されるまで、各フラグメントが追加された順序で、各フラグメントに対して呼び出します。
ヒント: Android 3.0 では、{@code android:onClick} 属性を使って、メニュー アイテムのクリックでの動作を XML で定義できます。 その属性値は、メニューを使ってアクティビティによって定義されるメソッド名である必要があります。 そのメソッドは、パブリックであり、1 つの {@link android.view.MenuItem} パラメータを使用できる必要があります。システムがこのメソッドを呼び出すと、選択したメニュー アイテムが渡されます。 詳細と例については、「Menu Resource」のドキュメントをご覧ください。
ヒント: アプリケーションに複数のアクティビティが含まれていて、その一部で同じオプション メニューが提供されている場合、{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} と {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} メソッドのみを実装するアクティビティを作成することを検討します。 その後、同じオプション メニューを共有する必要のある各アクティビティのこのクラスを拡張します。 この方法で、メニューの動作を継承するメニュー アクションとそれぞれの子クラスを処理するためのコードを 1 セットで管理できます。子孫アクティビティの 1 つにメニュー アイテムを追加する場合は、そのアクティビティの {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} をオーバーライドします。 元のメニュー アイテムが作成されるように、{@code super.onCreateOptionsMenu(menu)} を呼び出し、{@link android.view.Menu#add(int,int,int,int) menu.add()} で新しいメニュー アイテムを追加します。 各メニュー アイテムのスーパークラスの行動をオーバーライドすることもできます。
システムが {@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を呼び出した後、入力する {@link android.view.Menu} のインスタンスは残り、何らかの理由でメニューが無効にならない限り、{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} をもう一度呼び出すことはありません。 ただし、初期のメニュー状態を作成し、アクティビティのライフサイクル中に変更しないという目的の場合に限って、{@link android.app.Activity#onCreateOptionsMenu(Menu) onCreateOptionsMenu()} を使用する必要があります。
アクティビティのライフサイクル中に発生するイベントに基づいてオプション メニューを変更する場合は、{@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} メソッドでそれを実行できます。 このメソッドは、現在存在している {@link android.view.Menu} オブジェクトを渡し、それを編集(アイテムの追加、削除、無効化など)できるようにします。 (フラグメントでも {@link android.app.Fragment#onPrepareOptionsMenu onPrepareOptionsMenu()} コールバックが提供されます)。
Android 2.3.x 以前では、ユーザーが Menu ボタンを押してオプション メニューを開くたびに、システムによって {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} が呼び出されます。
Android 3.0 以降では、メニュー アイテムがアクションバーに表示されるときに、オプション メニューが常に開かれるとみなされます。 イベントが発生し、メニューをアップデートするときは、{@link android.app.Activity#invalidateOptionsMenu invalidateOptionsMenu()} を呼び出して、システムが {@link android.app.Activity#onPrepareOptionsMenu(Menu) onPrepareOptionsMenu()} を呼び出すようリクエストする必要があります。
注: 現在フォーカスされている {@link android.view.View} に基づいてオプション メニューでアイテムを変更しないでください。 タッチモードの場合(ユーザーがトラックボールやリモコンの矢印ボタンを使うとき)、ビューはフォーカスを取得できないため、オプション メニューのアイテム変更のベースとしてフォーカスを使用しないでください。 {@link android.view.View} に状況依存のメニュー アイテムを提供する場合は、コンテキスト メニューを使います。
コンテキスト メニューでは、UI の特定のアイテムやコンテキスト フレームに影響するアクションが提供されます。どのビューでもコンテキスト メニューを提供できますが、ほとんどの場合は、{@link android.widget.ListView}、{@link android.widget.GridView}、各アイテムでユーザーが直接実行できるその他のビュー コレクションのアイテムに使用されます。
コンテキスト アクションを提供するには次の 2 つの方法があります。
注: コンテキスト アクション モードは、Android 3.0(API レベル 11)以降で使用可能で、使用可能な場合にコンテキスト アクションを表示するのに適した方法です。 アプリで 3.0 以前のバージョンをサポートする場合、その端末ではフローティング コンテキスト メニューを使う必要があります。
フローティング コンテキスト メニューを提供するには:
アクティビティで {@link android.widget.ListView} や {@link android.widget.GridView} が使用され、各アイテムに同じコンテキスト メニューを提供する場合、{@link android.widget.ListView} や {@link android.widget.GridView} を {@link android.app.Activity#registerForContextMenu(View) registerForContextMenu()} に渡してコンテキスト メニューにすべてのアイテムを登録します。
登録されたビューが長押しクリック イベントを受け取ると、システムは {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu onCreateContextMenu()} メソッドを呼び出します。 通常、ここでメニュー リソースをインフレートして、メニュー アイテムを定義します。次に例を示します。
@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); }
{@link android.view.MenuInflater} では、メニュー リソースからコンテキスト メニューをインフレートできます。そのコールバック メソッド パラメータには、ユーザーが選択した {@link android.view.View} と選択されたアイテムに関する追加情報を提供する {@link android.view.ContextMenu.ContextMenuInfo} オブジェクトが含まれます。 アクティビティに、それぞれ別のコンテキスト メニューを提供する複数のビューがある場合、これらのパラメータを使ってインフレートするコンテキスト メニューを決定できます。
ユーザーがメニュー アイテムを選択すると、システムによってこのメソッドが呼び出され、適切なアクションを実行できるようになります。 次に例を示します。
@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); } }
{@link android.view.MenuItem#getItemId()} メソッドは、選択されたメニュー アイテムの ID を照会します。XML でメニューを定義するのセクションで説明されているように、{@code android:id} 属性を使って XML で各メニュー アイテムを割り当てる必要があります。
メニュー アイテムを正常に処理する場合、{@code true} を返します。メニュー アイテムを処理しない場合は、スーパークラスの実装にメニュー アイテムを渡す必要があります。 アクティビティにフラグメントが含まれる場合、そのアクティビティは最初にこのコールバックを受け取ります。 未処理のときにスーパークラスを呼び出すと、システムは {@code true} や {@code false} が返されるまで、各フラグメントのそれぞれのコールバック メソッドに 1 つずつ、各フラグメントが追加された順序でイベントを渡します。 {@link android.app.Activity} と {@code android.app.Fragment} のデフォルトの実装では {@code false} が返されるため、未処理のときは常にスーパークラスを呼び出す必要があります。
コンテキスト アクション モードは、{@link android.view.ActionMode} のシステム実装で、ユーザーによるコンテキスト アクション実行のための操作に焦点が置かれています。 ユーザーがアイテムを選択してこのモードを有効にすると、画面の最上部にコンテキスト アクションバーが表示され、現在選択中のアイテムで実行できるアクションが表示されます。 このモードが有効な間は、ユーザーは複数のアイテムを選択したり(許可されている場合)、アイテムを選択解除したり、アクティビティ内を移動し続けたり(許可されている範囲内で)することができます。 ユーザーがすべてのアイテムの選択を解除したり、Back ボタンをしたり、またはバーの左端で Done アクションを選択したりすると、このアクション モードは無効になり、コンテキスト アクションバーは表示されなくなります。
注: コンテキスト アクションバーをアクションバーと関連付ける必要はありません。 コンテキスト アクションバーが、視覚的にアクションバーの位置にかかる場合でも、個別に操作できます。
Android 3.0(API レベル 11)以降向けに開発中の場合、通常はフローティング コンテキスト メニューではなく、コンテキスト アクション モードを使ってコンテキスト アクションを表示します。
コンテキスト アクションを提供するビューでは、通常は次の 2 つのイベントのいずれかまたは両方で、コンテキスト アクションを呼び出す必要があります。
アプリケーションがどのようにコンテキスト アクション モードを呼び出して各アクションの動作を定義するかは、デザインによって異なります。 基本的に次の 2 つのデザインがあります。
次のセクションでは、各シナリオに必要な設定について説明します。
ユーザーが特定のビューを選択するときにのみ、コンテキスト アクション モードを呼び出すには、次のことを行う必要があります。
次に例を示します。
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { // Called when the action mode is created; startActionMode() was 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, but // may 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) { mActionMode = null; } };
これらのイベント コールバックは、これらのそれぞれもイベントに関連する {@link android.view.ActionMode} オブジェクトを渡すこと以外は、オプション メニューのコールバックとほぼ同じです。{@link android.view.ActionMode} API を使って、{@link android.view.ActionMode#setTitle setTitle()} と {@link android.view.ActionMode#setSubtitle setSubtitle()}(選択されているアイテム数を表示するのに役立つ)でタイトルとサブタイトルを変更するなど、CAB にさまざまな変更を行うことができます。
また、上記のサンプルでは、アクション モードが破棄されるときに {@code mActionMode} 変数が null に設定されます。 次のステップでは、それがどのように初期化され、アクティビティやフラグメントでどのようにメンバー変数を保存するのが役立つかについて説明します。
someView.setOnLongClickListener(new View.OnLongClickListener() { // Called when the user long-clicks on someView public boolean onLongClick(View view) { if (mActionMode != null) { return false; } // Start the CAB using the ActionMode.Callback defined above mActionMode = getActivity().startActionMode(mActionModeCallback); view.setSelected(true); return true; } });
{@link android.app.Activity#startActionMode startActionMode()} を呼び出すと、システムは作成された {@link android.view.ActionMode} を返します。 メンバー変数でこれを保存すると、その他のイベントに応じてコンテキスト アクションバーを変更できます。 上記の例では、{@link android.view.ActionMode} を使って、{@link android.view.ActionMode} インスタンスがアクティブな状態である場合に、アクション モードを開始する前にメンバーが null であるかどうかを確認して、そのインスタンスが再作成されないようにしています。
{@link android.widget.ListView} や {@link android.widget.GridView}(または {@link android.widget.AbsListView} の別の拡張)にアイテムのコレクションがあり、ユーザーがバッチ アクションを実行できるようにする場合は、次のことを行う必要があります。
次に例を示します。
ListView listView = getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); listView.setMultiChoiceModeListener(new MultiChoiceModeListener() { @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { // Here you can do something when items are selected/de-selected, // such as update the title in the CAB } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // Respond to clicks on the actions in the CAB switch (item.getItemId()) { case R.id.menu_delete: deleteSelectedItems(); mode.finish(); // Action picked, so close the CAB return true; default: return false; } } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // Inflate the menu for the CAB MenuInflater inflater = mode.getMenuInflater(); inflater.inflate(R.menu.context, menu); return true; } @Override public void onDestroyActionMode(ActionMode mode) { // Here you can make any necessary updates to the activity when // the CAB is removed. By default, selected items are deselected/unchecked. } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // Here you can perform updates to the CAB due to // an {@link android.view.ActionMode#invalidate} request return false; } });
これだけです。これで、ユーザーが長押しクリックでアイテムを選択すると、システムは {@link android.widget.AbsListView.MultiChoiceModeListener#onCreateActionMode onCreateActionMode()} メソッドを呼び出して、特定のアクションでコンテキスト アクションバーを表示するようになります。 コンテキスト アクションバーが表示されている間は、追加のアイテムを選択できます。
コンテキスト アクションによって一般的なアクション アイテムが提供されるとき、ユーザーが長押しクリックの動作に気付かない可能性があることを考慮して、アイテムを選択できるようにチェックボックスや同様の UI 要素を追加したい場合もあります。 ユーザーがチェックボックスをオンにするとき、{@link android.widget.AbsListView#setItemChecked setItemChecked()} でオンにされた状態にそれぞれのリストアイテムを設定して、コンテキスト アクション モードを呼び出すことができます。
図 4.右上のオーバーフローボタンに固定された Gmail アプリのポップアップ メニュー。
{@link android.widget.PopupMenu} は {@link android.view.View} に固定されるモーダル メニューです。スペースがある場合にはアンカービューの下に、スペースがない場合はビューの上に表示されます。 次の場合に役立ちます。
注: これは、通常は選択したコンテンツに影響するアクション用であるコンテキスト メニューとは異なります。 選択したコンテンツに影響するアクションには、コンテキスト アクション モードやフローティング コンテキスト メニューを使います。
注: {@link android.widget.PopupMenu} は API レベル 11 以降で使用できます。
XML でメニューを定義する場合の、ポップアップ メニューの表示方法について、次に示します。
ポップアップ メニューを表示する {@link android.R.attr#onClick android:onClick} 属性を含むボタンの一例を以下に示します。
<ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_overflow_holo_dark" android:contentDescription="@string/descr_overflow_button" android:onClick="showPopup" />
アクティビティでは、次のようにポップアップ メニューが表示されます。
public void showPopup(View v) { PopupMenu popup = new PopupMenu(this, v); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.actions, popup.getMenu()); popup.show(); }
API レベル 14 以降では、{@link android.widget.PopupMenu#inflate PopupMenu.inflate()} でメニューをインフレートする 2 行を組み合わせることができます。
ユーザーがアイテムを選択するか、メニュー領域外をタップすると、メニューが閉じます。 {@link android.widget.PopupMenu.OnDismissListener} を使って dismiss イベントをリッスンできます。
ユーザーがアイテム メニューを選択するときにアクションを実行するには、{@link android.widget.PopupMenu.OnMenuItemClickListener} インターフェースを実装し、{@link android.widget.PopupMenu#setOnMenuItemClickListener setOnMenuItemclickListener()} を呼び出して {@link android.widget.PopupMenu} でそれを登録する必要があります。 ユーザーがアイテムを選択すると、インターフェースで {@link android.widget.PopupMenu.OnMenuItemClickListener#onMenuItemClick onMenuItemClick()} コールバックが呼び出されます。
次に例を示します。
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; } }
メニュー グループは、特定の特徴を共有するメニュー アイテムのコレクションです。グループを使って次のことを実行できます。
メニュー リソースの {@code <group>} 要素内で {@code <item>} 要素をネストするか、{@link android.view.Menu#add(int,int,int,int) 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 つのアイテムの特徴を変更できます。 システムが、グループ化されたアイテムを分けることもありません。 たとえば、各アイテムに {@code android:showAsAction="ifRoom"} を宣言する場合、その両方がアクションバーまたはアクション オーバーフローに表示されます。
メニューは、オプションのオンとオフを切り替えるインターフェースとして役立ちます。スタンドアロンのオプションにはチェックボックスを、相互に排他的なオプションのグループにはラジオボタンを使います。 図 5 に、ラジオボタン付きのオンにできるアイテムを含むサブメニューを示します。
注: アイコン メニューのメニュー アイテム(オプション メニューから)ではチェックボックスやラジオボタンを表示できません。 アイコン メニューのアイテムをオンにできるようにする場合、状態が変わるごとにアイコンやテキストを入れ替えて、オンにされた状態を手動で示す必要があります。
個々のメニュー アイテムには {@code <item>} 要素の {@code android:checkable} 属性を、グループ全体には {@code <group>} 要素の {@code 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>
{@code android:checkableBehavior} 属性では、次のいずれかが許容されます。
{@code <item>} 要素の {@code android:checked} 属性を使って、デフォルトのオンにされた状態をアイテムに適用でき、{@link android.view.MenuItem#setChecked(boolean) setChecked()} メソッドを使ってコード内でそれを変更できます。
オンにできるアイテムが選択されると、システムは {@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のような、それぞれの item-selected コールバック メソッドを呼び出します。 チェックボックスやラジオボタンによって自動的にその状態が変わることはないため、ここでチェックボックスの状態を設定する必要があります。 {@link android.view.MenuItem#isChecked()} で、アイテムの現在の状態(ユーザーが選択する前の状態)を照会できます。その後、{@link android.view.MenuItem#setChecked(boolean) setChecked()} でオンにされた状態を設定します。 次に例を示します。
@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); } }
この方法でオンにされた状態を設定しない場合には、アイテム(チェックボックスまたはラジオボタン)の表示状態はユーザーがオンにしたときに変更されません。 状態を設定すると、アクティビティはアイテムのオンにされた状態を維持して、ユーザーが後でメニューを開いたときに、開発者が設定したオンにされた状態が表示されるようになります。
注: オンにできるメニュー アイテムは、セッション単位ベースのみでの使用を意図したもので、アプリケーションが破棄された後は、保存されません。 ユーザー用に保存するアプリケーション設定がある場合は、共有のプリファレンスを使ってデータを保存してください。
{@link android.content.Intent} を使ってメニュー アイテムでアクティビティが起動されるようにしたい場合もあります(自分のアプリケーションのアクティビティであるか、別のアプリケーションのアクティビティであるかにかかわらず)。 使用するインテントがわかっていて、インテントを開始する必要のある特定のメニュー アイテムがある場合は、適切な on-item-selected コールバック メソッド({@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} のような)中に、{@link android.app.Activity#startActivity(Intent) startActivity()} でインテントを実行できます。
ただし、ユーザーの端末にインテントを処理するアプリケーションが含まれているかどうかが不明な場合、それを呼び出すメニュー アイテムを追加すると、そのインテントによってアクティビティが解決されないためにメニュー アイテムが機能しなくなることがあります。 これを解決するために、Android では、インテントを処理する端末で Android によってアクティビティが検出されるときに、メニュー アイテムがメニューに動的に追加されるようにします。
インテントを受け入れる使用可能なアクティビティに基づいてメニュー アイテムを追加するには:
インテントを満たすアプリケーションがインストールされていない場合、メニュー アイテムは追加されません。
注: {@link android.content.Intent#CATEGORY_SELECTED_ALTERNATIVE} は、現在画面で選択されている要素の処理に使われます。 このため、{@link android.app.Activity#onCreateContextMenu(ContextMenu,View,ContextMenuInfo) onCreateContextMenu()} でメニューを作成するときにのみ、それが使われる必要があります。
次に例を示します。
@Override public boolean onCreateOptionsMenu(Menu menu){ super.onCreateOptionsMenu(menu); // Create an Intent that describes the requirements to fulfill, to be included // in our 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 applications. menu.addIntentOptions( R.id.intent_group, // Menu group to which new items will be 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 our requirements 0, // Additional flags to control items (none) null); // Array of MenuItems that correlate to specific items (none) return true; }
定義されたインテントに一致するインテント フィルタが提供されていることを見つけた各アクティビティに対して、メニュー アイテムのタイトルにインテント フィルタの android:label
の値を、メニュー アイテムのアイコンにアプリケーション アイコンを使って、メニュー アイテムが追加されます。
{@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[])
addIntentOptions()} メソッドによって、追加されたメニュー アイテム数が返されます。
注: {@link android.view.Menu#addIntentOptions(int,int,int,ComponentName,Intent[],Intent,int,MenuItem[]) addIntentOptions()} を呼び出すとき、最初の引数で指定されたメニュー グループによって、すべてのメニュー アイテムがオーバーライドされます。
他のアプリケーションにアクティビティのサービスを提供して、アプリケーションを他のメニューに含めることができるようにすることもできます(前述の役割を逆にする)。
他のアプリケーションのメニューに含まれるようにするには、通常どおりインテント フィルタを定義する必要がありますが、インテント フィルタのカテゴリに、{@link android.content.Intent#CATEGORY_ALTERNATIVE} や {@link android.content.Intent#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>
インテント フィルタの記述の詳細については、「インテントとインテント フィルタ」をご覧ください。
この方法を使ったサンプル アプリケーションについては、Note Pad のサンプルコードをご覧ください。