Menu由兩種形式

Option Menu

當我們按下Menu的硬件按鈕時,Option Menu將被觸發顯示,最多可以顯示6個選項的icon菜單,如果選項多於6個,第6個選項顯示爲“More“,點擊可以進入擴展菜單。我們將在Android學習筆記(十一):Activity-ListView的例子一的基礎上來學習Option Menu,也就是一個基於activity的菜單。

在這個例子中,我們給出一個有7個選項(多餘最多顯示6個item)的例子,可以設置List中item之間分割線的粗細。

步驟1:創建Menu

1.1 設置Menu各個item的ID

    private static final int EIGHT_ID = Menu.FIRST +1;
    private static final int SIXTEEN_ID = Menu.FIRST+2;
    private static final int TWENTY_FOUR_ID = Menu.FIRST+3;
    private static final int TWO_ID = Menu.FIRST+4;
    private static final int THIRTY_TWO_ID = Menu.FIRST+5;
    private static final int FORTY_ID = Menu.FIRST+6;
    private static final int ONE_ID = Menu.FIRST+7;

其中Menu.FIRST在reference中描述爲:First value for group and item identifier integers.我們可以理解爲ID設置的最小數值。

1.2 創建Menu

在用戶第一次按下Menu鍵的使用,將觸發onCreateOptionsMenu(),我們將在此創建我們的菜單

    public boolean onCreateOptionsMenu(Menu menu) {
        /*第一個參數是groupId,如果不需要可以設置爲Menu.NONE。將若干個menu item都設置在同一個Group中,可以使用setGroupVisible(),setGroupEnabled(),setGroupCheckable()這樣的方法,而不需要對每個item都進行setVisible(), setEnable(), setCheckable()這樣的處理,這樣對我們進行統一的管理比較方便
       * 第二個參數就是item的ID,我們可以通過menu.findItem(id)來獲取具體的item
       * 第三個參數是item的順序,一般可採用Menu.NONE,具體看本文最後MenuInflater的部分
       * 第四個參數是顯示的內容,可以是String,或者是引用Strings.xml的ID*/
        menu.add(Menu.NONE,ONE_ID,Menu.NONE,"1 Pixel");
        menu.add(Menu.NONE, TWO_ID, Menu.NONE, "2 Pixels");
        menu.add(Menu.NONE, EIGHT_ID, Menu.NONE, "8 Pixels");
        menu.add(Menu.NONE, SIXTEEN_ID, Menu.NONE, "16 Pixels");
        menu.add(Menu.NONE, TWENTY_FOUR_ID, Menu.NONE, "24 Pixels");
        menu.add(Menu.NONE, THIRTY_TWO_ID, Menu.NONE, "32 Pixels");
        menu.add(Menu.NONE, FORTY_ID, Menu.NONE, "40 Pixels");

        return super.onCreateOptionsMenu(menu);
    }

如果我們需要增加圖標,也很簡單,如下。

        MenuItem item1 = menu.add(Menu.NONE,ONE_ID,Menu.NONE,"1 Pixel");
        item1.setIcon(R.drawable.android_normal);

運行,按Menu鍵,可以獲得我們的Menu,如下圖,第一個圖是顯示效果,第二個圖是按了菜單中的More後顯示的效果,第三個圖我們在上面的基礎上,再增加三個item,按More後的顯示效果。

步驟2:Menu觸發

Menu觸發比較簡單,Activity在Memu後會觸發onOptionsItemSelected()進行處理。如下:

    public boolean onOptionsItemSelected(MenuItem item) {
        ... ... 加入我們的處理 ... ...
        return super.onOptionsItemSelected(item);
    }

在這個例子我們加入的處理如下。右圖爲選擇24pix的顯示結果

            switch (item.getItemId()) { //獲取Id
              case ONE_ID:
                getListView().setDividerHeight(1);
                break;
              case EIGHT_ID:
                getListView().setDividerHeight(8);
                break;

              ... 類同,設置分割線的粗細,略去... 
              default:
                break;
            }

步驟3:增加某些變化

在上面的步驟中,已經學習了Option Menu的基本處理,但是我們需要增加一些變化

3.1 每次顯示menu時根據實際的情況進行適配

onCreateOptionsMenu()只在第一次按Menu按鍵時觸發,有些時候,我們希望每次顯示的菜單有一些變化,例如這個例子中,我們希望菜單不顯示當前的分割線高度,只出現需要改變的高度,如圖所示,當分割線爲16pix時,菜單將不出現16pix的item。這樣可以使用onPrepareOptionsMenu()。當用戶第一次按Menu鍵時,先執行onCreateOptionsMenu( ),然後執行onPrepareOptionsMenu();當用戶第二次,第三次,第N次按Menu建時,執行onPrepareOptionsMenu(),因此我們可以在onPrepareOptionsMenu()中處理每次的變化。本例如下

    public boolean onPrepareOptionsMenu(Menu menu) {
        /* 將所有的item設置有可視,好煩,想起了設置GourpID的好處,可以使用menu.setGroupVisible(Menu.NONE, true)代替。但是合理的,我們應當設置自己的GroupID,因此我們仍然每個item進行設置*/
        menu.findItem(ONE_ID).setVisible(true);
        menu.findItem(EIGHT_ID).setVisible(true);
        
... 類同,設置menu item可視,略去... 
        switch(getListView().getDividerHeight()){//如果需要設置的高度和當前的高度一致,不顯示。
        case 1:
            menu.findItem(ONE_ID).setVisible(false); 
            break;
        case 8:
            menu.findItem(EIGHT_ID).setChecked(true);
            break;

        ... 類同,略去...
        default:
            break;
        }     
        return super.onPrepareOptionsMenu(menu);
    }

3.2 快捷鍵

現在的智能手機一般都是直板不帶鍵盤的,但是傳統手機可能代T9鍵盤,也可能是全鍵盤。Android支持快捷鍵,雖然可能不常用到,對於全鍵盤,我們可以在onCreateOptionsMenu()中加入下面代碼,這樣,在CTRL-A和Alt-A中都能觸發。

menu.findItem(ONE_ID).setAlphabeticShortcut('A');

對於T9鍵盤,由於模擬器不是T9鍵盤,也沒有T9的手機,最後的效果沒有實驗過,如下處理:

menu.setQwertyMode(true);
menu.findItem(TWO_ID).setNumericShortcut('2');

3.3 設置Item顯示CheckBox的格式

我們選取了其中兩item進行設置,如下:

1)在onCreateOptionsMenu()中設置這兩個item是可以顯示的是否checked的狀態:

        menu.findItem(EIGHT_ID).setCheckable(true);
        menu.findItem(FORTY_ID).setCheckable(true);

2)在onPrepareOptionsMenu()中,將如何和當前狀態一致這設置checked的狀態,例如:

case 8:
    menu.findItem(EIGHT_ID).setChecked(true);
    break;
case 40:
    menu.findItem(FORTY_ID).setChecked(true);
    break;

3)什麼時候可以顯示

讓我們看看這兩個的顯示結果,我們發現“8 pix"的情況下Menu沒有發生變化,而選擇40的時候,出現了變化。爲什麼會這樣?顯示的前提是有足夠位置顯示。在“8 pix“由於是Menu的第一頁的6個item,沒有足夠位置,而40px是More後的採用list的形式顯示,有足夠的位置,因此可以顯示。

同樣的,對於加Icom的例子,我們可以在第一頁中看到Icon,如果通過More的方式顯示後面的Icon,這個圖片是看不到的,Android會給據UI情況進行適配。

4)我們可以通過Group來處理:

menu.setGroupCheckable(Group_id, true, false);//在這個例子中可以使用Menu.NONE作爲Group_Id來實驗

第二個參數是是否允許checkable,而第三個參數很有意思,true表示可以可以單選,採用radio button的方式,如下左圖,false表示可以多選,如下右圖。

步驟4:子菜單

Android支持二級菜單,但是不支持三級等多級菜單。子菜單設置如下,在onCreateOptionsMenu(),如下:

//通過addSubMenu設置子菜單,作爲item加入Menu。參數和addMenu一致,爲了簡單,我們這裏的ID直接採用數字表示
SubMenu submenu = menu.addSubMenu(Menu.NONE, 100, Menu.NONE, "子菜單測試");
//在SubMenu中增加子菜單的item
submenu.add(Menu.NONE,101,Menu.NONE,"sub One");
submenu.add(Menu.NONE,102,Menu.NONE,"sub Two");
submenu.add(Menu.NONE,103,Menu.NONE,"sub Three");
submenu.add(Menu.NONE,104,Menu.NONE,"sub Four");

顯示如下,我們是加在原有菜單之後,因此需要按More查看:

Context Menu

Context Menu是用戶手指長按某個View觸發的菜單。處理如下:

步驟1:爲某個view註冊ContextMenu

例如在我們的例子中,在onCreate()中對整個ListView進行處理:

registerForContextMenu(getListView());

步驟2:創建ContextMenu

通過Override onCreateContextMenu()來創建Context Menu。如果我們爲多個View都註冊了ContextView,那麼我們可以通過第二個參數View v來判斷需要創建怎樣的菜單。第三個參數ContextMenuInfo和具體的View的特性有關,如果是list,它是List這中的item,這樣我們可以根據這個item的當前狀態,例如是否checked來處理menu。

    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        ... 設置Menu的處理,和Option Menu一樣 ....,同樣的支持子菜單
        super.onCreateContextMenu(menu, v, menuInfo);
    }

我們每一次常按widget,都會觸發onCreateContextMenu()的處理,這和Option Menu不一樣。每次處理完,ContextMenu都會discard,因此我們不要保留裏面的menu以及menu item對象用於其他的處理。

步驟3:點擊菜單觸發函數

觸發onContextItemSelected()。這裏麼只有一個MenuItem,因此在程序中,每個MenuItem的ID應該是唯一的,如果我們需要獲取MenuInfo,可以用item.getMenuInfo()來獲得。

    public boolean onContextItemSelected(MenuItem item) {
        ...  我們的處理內容...
        return super.onContextItemSelected(item);
    }

通過XML來定義Menu

Android學習筆記(十七):再談ListView中,利用LayoutInflater infalter =getLayoutInflater();從XML文件中獲取Layout的樣式。在Menu中也可以採用類似的方式。我們在onCreateOptionsMenu()中如下處理:

    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater menuInflater = new MenuInflater(getApplication());
        menuInflater.inflate(R.menu.chapter11_menu, menu);
        return super.onCreateOptionsMenu(menu);
    }

其中我們在res/menu目錄下面創建Menu的xml文件chapter11_menu.xml。我們通過下面的例子看看Menu XML文件如何編寫:

<?xml version="1.0" encoding="utf-8"?>
<!-- Menu對應一個Menu的格式 -->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- 我們分三種情況進行設置 -->
    
<!-- Part 1 :普通情況,我們增加三個MenuItem,item對應MenuItem的格式。item中的android:id直接就是item的ID,即我們menu.add()中的第二個參數。-->
   
<item android:id="@+id/c11_close"
    <!-- title爲顯示的文字,即menu.add()中的第三個參數的第四個參數,可採用@string/xxx -->
      android:title="Close"
     <!-- orderInCategory表明擺放的順序,不一定從0還是計算,但必須大於等於0,數值小的位於前,如果數值一樣,在我們這個例子中3又兩個值,則安順序擺放,此相當於menu.add()中的第三個參數order。當然我們建議從0,1,2,3....這樣依次給出,並且與XML行文的順序一致。-->
      android:orderInCategory = "3"
     <!-- icon設置圖標,不言自喻 -->
      android:icon="@drawable/android_focused" />
     <item android:id="@+id/c11_no_icon"
       android:orderInCategory = "2"
       android:title = "Sans Icon" />

     <item android:id="@+id/c11_disabled"
       android:orderInCategory="4"
       android:enabled="false"

       android:title="Disabled" />
    
<!-- Part 2 :Group的情況,我們在Group中放入2個item,如果我們要顯示3.4的方式,可以增加group的參數android:checkableBehavior來設置,single表示radio box,all表示checkbox,none表示checkable=flase。group中的android:id就是Gourp_ID,即menu.add()中的第一個參數。在這個例子中,我們設置這個group不可視,如果需要顯示,代碼爲:menu.setGroupVisible(R.id.c11_other_stuff, true);-->
      <groupandroid:id="@+id/c11_other_stuff"
      <!-- Item由android:orderInCategory來設置item的順序,在Group中我們可以通過menuCategory來設置另一個category,裏面的順序和default Category是不方在一起比較,例如這裏麼我們給出0和5,如圖所示,在顯示完default Category,再顯示這個sendonary的內容。 -->
        android:menuCategory="secondary"
        android:checkableBehavior="single"
        android:visible="false" >
           <item android:id="@+id/c11_later"
             android:orderInCategory="0"
             android:title="2nd-To-Last" />
           <item android:id="@+id/last"
              android:orderInCategory="5"
             android:title="Last" />

     </group>
     <!-- Part 3 :子menu的設置,將在menuItem內部嵌套一個<Menu>,在這個例子中的子菜單,試驗了快捷鍵的方式-->
     <itemandroid:id="@+id/c11_submenu"
       android:orderInCategory="3"
       android:title="A submenu"
>
           <menu>
               <item android:id="@+id/c11_non_ghost"
                 android:title="Non-Ghost"
                 android:visible="true"
                 android:alphabeticShortcut="n"/>
               <item android:id="@+id/c11_ghost"
                 android:title="Ghost"
                 android:visible="true"
                 android:alphabeticShortcut="g" />

           </menu>
      </item> <!-- end of Part 3 -->
</menu>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章