marunomaruno-memo

marunomaruno-memo

[Android] オプション・メニューとコンテキスト・メニュー

2012年03月05日 | Android
[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." の部分は表示から割愛
                                                                            以上