[Android] オプション・メニューとコンテキスト・メニュー ================================================================================ オプション・メニューは、実機によっては、画面とは別にある「メニュー」ボタン押下に よって表示されるコンポーネント。タブレットなどでは、画面上に「メニュー」ボタンが あったりする。 コンテキスト・メニューは、ビューの部品(たとえば、TextView など)を長押しすること で、そのコンポーネント上に表示されるメニューである。 メニューは、その項目数が 6 つ以内のときはグリッド表示され、7 つ以上になったとき は 6 つ目のメニュー項目が「その他」になり、それをクリックすることで、残りのメニ ューが表示される。 つぎの Activity クラスのメソッドをオーバーライドすることで、オプション・メニュー を設定する。 public boolean onCreateOptionsMenu(Menu menu) オプション・メニュー生成時のハンドラー public boolean onMenuOpened(int featureId, Menu menu) オプション・メニューを開いたときのハンドラー public void onOptionsMenuClosed(Menu menu) オプション・メニューを閉じたときのハンドラー public boolean onOptionsItemSelected(MenuItem item) オプション・メニューの項目選択時のハンドラー つぎの Activity クラスのメソッドをオーバーライドすることで、コンテキスト・メニ ューを設定する。 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) コンテキスト・メニュー生成時のハンドラー public void onContextMenuClosed(Menu menu) コンテキスト・メニューを閉じたときのハンドラー public boolean onContextItemSelected(MenuItem item) コンテキスト・メニューの項目選択時のハンドラー なお、コンテキスト(ビュー)とこのコンテキスト・メニューとを紐づけるのは、Activity. registerForContextMenu() メソッドによる。 また、オプション・メニュー、コンテキスト・メニュー共通で、その項目選択時のハンド ラーとして、次のメソッドがある。 public boolean onMenuItemSelected(int featureId, MenuItem item) ▲ アクティビティ 上記のメソッドをオーバーライドして、その動きを確認している。 □ Menu01Activity.java --- package jp.marunomaruno.android.menu; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.view.ContextMenu.ContextMenuInfo; import android.widget.TextView; import android.widget.Toast; import jp.marunomaruno.android.menu.R; public class Menu01Activity extends Activity { private static final int TOAST_DURATION = Toast.LENGTH_SHORT; private Context context; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); context = this; // コンテキスト・メニューの設定 TextView text1 = (TextView) findViewById(R.id.text1); registerForContextMenu(text1); // (1) } @Override public boolean onCreateOptionsMenu(Menu menu) { // (2) super.onCreateOptionsMenu(menu); // (3) MenuItem item1 = menu.add("アイスクリーム"); // (4) MenuItem item2 = menu.add("あられ"); SubMenu sub3 = menu.addSubMenu("あずき ..."); // (5) sub3.add("つぶあん"); // (6) sub3.add("こしあん"); return true; // (7) } @Override public boolean onMenuOpened(int featureId, Menu menu) { // (8) String message = String.format( "onMenuOpened(): featureId: %d, menu: ¥"%s¥"", featureId, menu); Toast.makeText(context, message, TOAST_DURATION).show(); System.out.println(message); return super.onMenuOpened(featureId, menu); } @Override public void onOptionsMenuClosed(Menu menu) { // (9) String message = String.format("onOptionsMenuClosed(): menu: ¥"%s¥"", menu); Toast.makeText(context, message, TOAST_DURATION).show(); System.out.println(message); super.onOptionsMenuClosed(menu); } @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { // (10) String message = String.format( "onMenuItemSelected(): featureId: %d, item: ¥"%s¥"", featureId, item); Toast.makeText(context, message, TOAST_DURATION).show(); System.out.println(message); return super.onMenuItemSelected(featureId, item); } @Override public boolean onOptionsItemSelected(MenuItem item) { // (11) String message = String.format("onOptionsItemSelected(): item: ¥"%s¥"", item); Toast.makeText(context, message, TOAST_DURATION).show(); System.out.println(message); return super.onOptionsItemSelected(item); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // (12) menu.setHeaderTitle("Context menu"); // (13) MenuItem item1 = menu.add("Apple"); MenuItem item2 = menu.add("Banana"); SubMenu sub3 = menu.addSubMenu("Chocolate ..."); sub3.add("Black"); sub3.add("White"); } @Override public void onContextMenuClosed(Menu menu) { // (14) String message = String.format("onContextMenuClosed(): menu: ¥"%s¥"", menu); Toast.makeText(context, message, TOAST_DURATION).show(); System.out.println(message); super.onContextMenuClosed(menu); } @Override public boolean onContextItemSelected(MenuItem item) { // (15) String message = String.format("onContextItemSelected(): item: ¥"%s¥"", item); Toast.makeText(context, message, TOAST_DURATION).show(); System.out.println(message); return super.onContextItemSelected(item); } } --- (1) ビューのコンポーネントにコンテキスト・メニューを登録する テキスト・ビューに対し、コンテキスト・メニューを登録する。 registerForContextMenu(text1); // (1) ・Activity クラスのメソッド --- void registerForContextMenu(View view) --- (2)(3)(7) オプション・メニューを生成したときの処理 アプリケーション起動時に、オプション・メニューは生成される。 public boolean onCreateOptionsMenu(Menu menu) { // (2) onCreateOptionsMenu() の先頭で、スーパークラスのメソッドを実行する。 super.onCreateOptionsMenu(menu); // (3) メニューが完成したので、true を返す。 return true; // (7) (4) オプション・メニューに項目を追加する onCreateOptionsMenu() メソッドの引数で、Menu オブジェクトが渡ってくるので、これ に対し、add() メソッドを使って、メニューの項目を追加する。 MenuItem item1 = menu.add("アイスクリーム"); // (4) ・Menu に項目を追加する主なメソッド(すべて abstract なので、その記述を省略) --- MenuItem add(CharSequence title) MenuItem add(int groupId, int itemId, int order, int titleRes) MenuItem add(int titleRes) MenuItem add(int groupId, int itemId, int order, CharSequence title) --- groupId 通常は NONE でよい(グループ化するための項目) itemId 項目 ID order メニュー項目を追加する位置(通常は NONE) title, titleRes メニュー項目のテキストの文字列またはリソース ID --- (5)(6) オプション・メニューにサブ・メニューを追加する サブ・メニューを追加するには、addSubMenu() メソッドを使う。この返り値は SubMenu クラスになる。 SubMenu sub3 = menu.addSubMenu("あずき ..."); // (5) ・サブ・メニューを追加するメソッド(すべて abstract なので、その記述を省略) --- SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) SubMenu addSubMenu(CharSequence title) SubMenu addSubMenu(int titleRes) --- addSubMenu() メソッドで作ったサブ・メニューに、add() メソッドを使って項目を追加す る。 sub3.add("つぶあん"); // (6) ・サブ・メニューに項目を追加するメソッド(すべて abstract なので、その記述を省略、 メニューに項目を追加するメソッドと同じ) --- MenuItem add(CharSequence title) MenuItem add(int groupId, int itemId, int order, int titleRes) MenuItem add(int titleRes) MenuItem add(int groupId, int itemId, int order, CharSequence title) --- (8) オプション・メニューを開いたときの処理 onCreateOptionsMenu() メソッドは、アプリケーション起動時に実行されるだけなので、 オプション・メニューが開かれるたびに呼ばれるメソッドがある。 public boolean onMenuOpened(int featureId, Menu menu) { // (8) (9) オプション・メニューを閉じたときの処理 public void onOptionsMenuClosed(Menu menu) { // (9) (10) メニューの項目を選択したときの処理 このメソッドは、オプション・メニュー、コンテキスト・メニューで共通で使える。 まず、このメソッドが動き、その後、オプション・メニューのときは onOptionsItemSelected() メソッドが、コンテキスト・メニューのときは onContextItemSelected() メソッドが動く。 引数の item が選択したメニュー項目になる。 public boolean onMenuItemSelected(int featureId, MenuItem item) { // (10) featureId は、メニューのパネルの ID。 メニュー項目の情報は、以下のメソッドを使って取得する。 ・取得関係の主なメソッド(すべて abstract なので、その記述を省略) --- int getItemId() int getOrder() SubMenu getSubMenu() CharSequence getTitle() CharSequence getTitleCondensed() --- (11) オプション・メニューの項目を選択したときの処理 public boolean onOptionsItemSelected(MenuItem item) { // (11) MenuItem オブジェクトは、オプション・メニュー項目でも、サブ・メニュー項目でも、コ ンテキスト・メニュー項目でも同じである。 (12) コンテキスト・メニューを生成したときの処理 オプション・メニューと違い、コンテキスト・メニューを開くたびにこのメソッドが呼ばれ る。 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // (12) (13) コンテキスト・メニューのタイトルを設定する menu.setHeaderTitle("Context menu"); // (13) (14) コンテキスト・メニューを閉じたときの処理 public void onContextMenuClosed(Menu menu) { // (14) (15) コンテキスト・メニューの項目を選択したときの処理 public boolean onContextItemSelected(MenuItem item) { // (15) △ Menu インターフェース android.view.Menu オプション・メニュー、コンテキスト・メニューで使うインターフェース。 ・主なメソッド(すべて abstract なので、その記述を省略) --- MenuItem add(CharSequence title) MenuItem add(int groupId, int itemId, int order, int titleRes) MenuItem add(int titleRes) MenuItem add(int groupId, int itemId, int order, CharSequence title) SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) SubMenu addSubMenu(CharSequence title) SubMenu addSubMenu(int titleRes) void clear() void close() MenuItem findItem(int id) MenuItem getItem(int index) boolean hasVisibleItems() void removeItem(int id) int size() --- △ SubMenu インターフェース android.view.SubMenu サブメニュー用のインターフェース。サブメニューは、末端のメニューで、この下はメニ ュー項目しか追加できない。 ・主なメソッド(すべて abstract なので、その記述を省略) --- void clearHeader() MenuItem getItem() SubMenu setHeaderIcon(Drawable icon) SubMenu setHeaderIcon(int iconRes) SubMenu setHeaderTitle(CharSequence title) SubMenu setHeaderTitle(int titleRes) SubMenu setHeaderView(View view) SubMenu setIcon(Drawable icon) SubMenu setIcon(int iconRes) --- △ MenuItem インターフェース android.view.MenuItem メニュー項目のインターフェース。 ・主なメソッド(すべて abstract なので、その記述を省略) --- int getItemId() ContextMenu.ContextMenuInfo getMenuInfo() int getOrder() SubMenu getSubMenu() CharSequence getTitle() CharSequence getTitleCondensed() boolean hasSubMenu() boolean isCheckable() boolean isChecked() boolean isEnabled() boolean isVisible() MenuItem setCheckable(boolean checkable) MenuItem setChecked(boolean checked) MenuItem setEnabled(boolean enabled) MenuItem setIcon(Drawable icon) MenuItem setIcon(int iconRes) MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener) MenuItem setTitle(CharSequence title) MenuItem setTitle(int title) MenuItem setTitleCondensed(CharSequence title) MenuItem setVisible(boolean visible) --- △ ContextMenu インターフェース android.view.ContextMenu コンテキスト・メニューを使うためには、つぎの手順が必要。 ・ロング・クリックするクライアント・オブジェクトに対して registerForContextMenu(View) を行う。 そして、つぎのメソッドをオーバーライドして、メニュー項目を追加する。 onCreateContextMenu(ContextMenu, View, ContextMenu.ContextMenuInfo) ・主なメソッド(すべて abstract なので、その記述を省略) --- void clearHeader() ContextMenu setHeaderIcon(Drawable icon) ContextMenu setHeaderIcon(int iconRes) ContextMenu setHeaderTitle(CharSequence title) ContextMenu setHeaderTitle(int titleRes) ContextMenu setHeaderView(View view) --- △ ContextMenuInfo インターフェース android.view.ContextMenu.ContextMenuInfo AdapterView などで使うマーカー・インターフェース。 メソッドなどは持っていない。 ▲ レイアウト コンテキスト・メニューを表示するための TextView を定義。 □ res/layout/main.xml --- <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/text1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#CCCC00" android:hint="@string/hint" android:text="" android:textAppearance="?android:attr/textAppearanceLarge" /> </LinearLayout> --- ▲ リソース □ res/values/strings.xml --- <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hint">ここを長押しするとコンテキストメニューが出る</string> <string name="app_name">Menu01</string> </resources> --- ▲ ログ メニュー関係のハンドラーの動きを確認。 --- ○ アプリケーション起動時 onCreateOptionsMenu(): menu: "MenuBuilder@46c02638" ○ オプション・メニュー選択時 onMenuOpened(): featureId: 0, menu: "MenuBuilder@46c02638" onMenuItemSelected(): featureId: 0, item: "アイスクリーム" onOptionsItemSelected(): item: "アイスクリーム" onOptionsMenuClosed(): menu: "MenuBuilder@46c02638" ○ オプション・メニューで、サブ・メニュー選択時 onMenuOpened(): featureId: 0, menu: "MenuBuilder@46c02638" onMenuItemSelected(): featureId: 0, item: "あずき ..." onOptionsItemSelected(): item: "あずき ..." onMenuItemSelected(): featureId: 0, item: "つぶあん" onOptionsItemSelected(): item: "つぶあん" ○ コンテキスト・メニュー選択時 onCreateContextMenu(): menu: "ContextMenuBuilder@46c2f3d0" onMenuItemSelected(): featureId: 6, item: "Banana" onContextItemSelected(): item: "Banana" onContextMenuClosed(): menu: "ContextMenuBuilder@46c2f3d0" ○ コンテキスト・メニューで、サブ・メニュー選択時 onCreateContextMenu(): menu: "ContextMenuBuilder@46c43598" onMenuItemSelected(): featureId: 6, item: "Chocolate ..." onContextItemSelected(): item: "Chocolate ..." onMenuItemSelected(): featureId: 6, item: "White" onContextItemSelected(): item: "White" onContextMenuClosed(): menu: "SubMenuBuilder@46c44618" --- ※パッケージ名 "com.android.internal.view.menu." の部分は表示から割愛 以上