從零開始--系統深入學習android(實踐-讓我們開始寫代碼-Android框架學習-3. 菜單)


第3章 菜單

在許多不同類型的應用中,菜單通常是一種用戶界面組件。為了提供給用戶提供熟悉且一致的體驗,你需要使用菜單API來展示用戶動作和你Activity中的其他選項。

從安卓3.0系統(API level 11)開始,安卓設備已經不再需要提供專用的菜單按鍵。基於這種變化,安卓應用需要遠離原來所依賴的傳統6選項菜單盤,取而代之的是提供一個動作條來顯示普通用戶的動作。雖然設計方案和用戶使用菜單選項的方式已經改變,但是從語義上定義的一套動作和選項仍然是基於菜單API的。這份指導書將介紹在所有版本的安卓系統中如何去創建三個基本類型的菜單和動作:

1. 選項菜單和動作條

選項菜單對於一個應用的菜單項來說是首要的。你放置其中的動作一般是可以影響整個應用的,例如“搜索”、“寫郵件”和“設置”。假如你為2.3或者更低版本的安卓系統開發應用,那么用戶可以通過點擊菜單按鈕來顯示選項菜單盤。在安卓3.0或者更高的系統中,選項菜單中的選項作為屏幕上動作項和溢出的選項采用動作條顯示。從安卓3.0開始,菜單按鍵是不被贊成的(一些設備一個也沒有),所以你需要改為使用動作條來提供動作和其他選項的入口。

2. 上下文菜單和上下文的操作模式

上下文菜單是一種浮動的菜單,是在當用戶在一個元件上執行長按動作時顯示的。當開發平台為安卓3.0或者更高的時候,你需要使用上下文操作模式來使所選的內容產生動作。這種模式顯示的動作項會影響到在屏幕頂部條上選定的內容,並允許用戶選擇多項。

3. 彈出窗口菜單

彈出窗口菜單顯示一列被錨記為調用菜單列表的列表項。它很好的提供了一個涉及到具體內容或者提供一個命令的第二部分選項的溢出操作。在彈出菜單中的動作不會直接影響到相應的內容,這就是上下文操作所想要的。

3.1 在XML中定義菜單

針對所有的菜單類別,安卓系統都提供了一個標准的XML格式來定義菜單項。你可以在一個XML菜單資源中定義一個菜單和它的所有選項,取代了在activity代碼中建立菜單。你可以接着在你的活動中或者代碼段中擴展菜單資源(載入它作為一個菜單對象)。

使用菜單資源是一個很好的慣例,主要有幾個原因:

◆它更容易在XML中形象化菜單結構。

◆它把菜單的內容從你應用的行為代碼中脫離出來。

◆它允許你創建交替的菜單結構以適應不同平台版本,屏幕大小,和其他利用應用資源框架的結構。

定義一個菜單,需要在你項目的res/menu/目錄下創建一個XML文件以及使用下面這些元件創建菜單:

<menu>

定義一個菜單作為菜單項的容器。<menu>必須作為文件的根結點,這樣才能容納一個或多個<item>和<group>元素。

<item>

創建一個在菜單中表示一個單獨的選項的菜單項。這個元素可能需要包含<menu>網來創建一個子菜單。

<group>

<item>元件中可選且不可見的容器。它允許你去把菜單項歸類,所以它們可以分享特性例如激活狀態和可視狀態。

這里是一個命名為 game_menu.xml 的菜單實例,如代碼清單3-1所示:

<?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>

 

代碼清單3-1

<item>元件支持多種屬性,你可以用來定義一個項的樣式和行為。菜單上的選項包含了以下屬性:

android:id

菜單項唯一的的ID資源,當用戶選中這個選項時允許應用通過這個ID來識別這個菜單項。

android:icon

索引一個圖片資源作為該項的圖標。

android:title

索引一個字符串作為該項的標題

android:showAsAction

載明該項作為一個行為項什么時候和怎樣顯示在動作條中。

這些是你需要使用的最重要屬性,但是還有更多可用的屬性。

你可以通過增加一個<menu>元素作為<item>的子項,給任意菜單的項增加子菜單(除了子菜單本身以外)。當你的應用有大量的功能被組織成主題形式,例如電腦應用程序的菜單欄的選項(文件,編輯,查看等等)時子菜單是非常有用的。

如代碼清單3-2所示:

<?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>

 

代碼清單3-2

在你的應用中使用菜單,你可以使用MenuInflater.inflate()尋找需要的菜單資源文件(將文檔資源轉換成一個可編程的對象)。在接下來的章節,你將看到怎樣為每個菜單類型定位菜單文件。

3.2 創建選項菜單

選項菜單包含了動作以及其他與當前活動上下文相關的選項,例如"搜索","撰寫郵件"以及"設置"等.在你選項菜單中的選項出現在屏幕中的位置時根據你開發應用的版本而定的:

◆如果你開發的應用是基於Android 2.3.x(API級別10)或者更低的,那么當用戶點擊菜單按鈕時你的選項菜單的內容出現在屏幕的底部。例如圖像1.當菜單打開時,首先看到的是菜單圖標的部分,且最多可容納六個菜單項。如果你的菜單包含了多於六的菜單項,那么Android放置六個選項且其余的放入到溢出的菜單中,用戶可以通過選擇“更多”選項來打開(如圖3-1)。

 

圖 3-1 android2.3下系統自帶瀏覽器選項菜單

◆如果你開發的應用是基於Android 3.0(API級別11)或者更高的,那么菜單選項中的選項可以添加到動作條中。默認情況下,系統會放置所有選項在動作溢出欄中,用戶可以打開在動作條右邊的動作溢出圖標(或者如果設備菜單按鈕可用的話,用戶可以點擊它)。為了能夠快速的訪問重要的動作,你可以在相應的<item>元件中添加 android:showAsAction="ifRoom"使一些選項出現在動作條上(如圖3-2)。更多關於動作項和其他動作條行為的信息可以查看Action Bar說明。

注意:即使你的開發沒有基於Android 3.0或者更高版本,你也可以創建你自己的動作條布局取得相似的效果。

 

圖 3-2 android3.0以上系統的動作條(加上了動作溢出按鈕)

從你的Activity子類或者Fragment子類你可以聲明選項菜單的選項。假如你的Activity和Fragment都聲明了選項菜單的選項,那么它們將被集合在UI界面中。Activity的選項先顯示,然后才是每個Fragment按順序添加到Activity中。如果需要,你還可以在你需要移動的每個<item>元素中添加android:orderInCategory的屬性重新按次序添加菜單項。

指定一個Activity的選項菜單,需要覆寫 onCreateOptionMenu()這個方法(Fragment提供它們自己的onCreateOptionMenu()回調方法)。在這種方法下,你可以導入你的菜單資源(定義在XML文件中)到Menu提供的回調方法中。如代碼清單3-3所示:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

 

代碼清單3-3

 

你也可以使用add()方法添加菜單項以及使用findItem()方法取回選項,使用MenuItem APIs修改它們的屬性。

如果你已經開發了基於Android 2.3.x或者更低版本的應用,那么當用戶第一次打開菜單時系統可以調用onCreateOptionMenu()去創建選項菜單。

如果你已經開發的應用是基於Android 3.0或者更高版本的,當活動(Activity)啟動時系統可以調用onCreateOptionsMenu()在動作條上顯示選項。

3.2.1單擊事件處理

當用戶從選項菜單中選擇一個選項時(包括動作條中的動作選項),系統將會調用你的活動中的onOptionsItemSelected()方法。這種方法是通過MenuItem選擇的。你可以通過調用getItemId()來識別選項,那么它會返回一個菜單項中特定的ID(定義在菜單資源中的android:id或者通過add()方法賦予其一個整型數)。你可以對已知的菜單項來匹配這個ID去執行適當的動作。如代碼清單3-4所示:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.new_game:
            newGame();
            return true;
        case R.id.help:
            showHelp();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

 

代碼清單3-4

當你成功的處理了一個菜單項,則會返回true值。如果你不能處理一個菜單項,那么你需要調用onOptionsItemSelected()基類來實現(默認實現方法返回false值)

如果你的Activity包含Fragment,那么系統首先會為Activity調用onOptionsItemSelected(),然后才是每個Fragment(每個Fragment已經按順序添加)直到有一個返回true值,或者所有的片段都被調用了。

提示:Android 3.0在XML中的菜單項中為你增加了定義點擊行為的能力,使用android:onClick屬性即可。屬性的值必須使用菜單的Activity中定義的方法的名稱。當系統調用這個方法的時候,方法必須是公共的且接受單獨的MenuItem參數。且它是通過菜單項選擇的。

提示:如果你的應用包含多個Activities且其中有一部分提供相同的選項菜單,你可以創建一個Activity只實現onCreateOptionsMenu()和onOptionsItemSelected()這兩個方法。然后每個需要使用這個選項菜單的Activity繼承這個類。這樣的話,你可以管理一部分代碼來處理菜單動作且每個子類都集成菜單的動作。如果你想要給子Activity增加菜單項,只要在這個Activity中覆寫onCreateOptionsMenu()這個方法即可。調用super.onCreateOptionsMenu(menu)那么原菜單項就被創建了,然后使用menu.add()添加新的菜單項.當然你也可以為個別的菜單項復寫基類的動作。

3.2.2運行時改變菜單項

在系統調用onCreateOptionsMenu()之后,它保留了你填充菜單中的一個實例且不會再調用onCreateOptionsMenu(),除非菜單出於某種原因失效了。然而,你可以使用onCreateOptionsMenu()去創建一個有效的菜單狀態且不能在Activity的生命周期內改變。如果你想要在Activity的生命周期內基於事件修改選項菜單,你需要在onPrepareOptionsMenu()方法中實現。只有目前存在菜單對象這個方法才能通過,那么你就可以修改它,例如增加,移除或者使選項失效。(Fragment也可以提供一個onPrepareOptionsMenu()的回調)。

在Android 2.3.x或者更低的版本中,當用戶每次打開選項菜單(通過點擊菜單按鈕)時系統都會調用onPrepareOptionsMenu()。在Android 3.0或者更高版本中,當菜單項提交在動作條時選項菜單被認為是始終打開的。當一個事件發生且你想要執行一個菜單的更新,那么你必須調用invalidateOptionsMenu()這個方法去反饋系統調用的onPrepareOptionsMenu()方法。

注意:你永遠不應該改變基於在選項菜單中目前處於焦點View的的選項。當其處於觸點狀態(用戶沒有使用循跡球或者d-pad),視圖不能處於焦點狀態,所以你永遠不能在選項菜單中使用焦點來改變選項。假如你想要為視圖(View)提供一個上下文敏感的菜單項,請使用上下文菜單。

3.3 創建上下文菜單

一個上下文菜單可以提供影響一個特殊選項或者UI中上下文的框架的動作。你可以為任何界面提供一個上下文菜單,但是它們通常在ListView、GridView或者用戶可以在每個選項中直接執行的動作的其他界面分類中使用。這里有兩種方法提供一個上下文動作:

◆在浮動的上下文菜單中。當用戶在一個聲明支持上下文菜單的界面中執行一個長點擊(按住並保持),那么這個菜單將作為一個菜單項浮動列表顯示(類似對話框)。用戶可以每次在一個選項上執行一個上下文動作。

◆在上下文動作模式下。這種模式是系統實現的動作模式,在屏幕頂部顯示上下文動作條動作條影響所選選項的動作選項的模式。當這種模式被激活,用戶可以一次在一個動作中執行多個選項(如果你的應用允許這樣)。

注意:上下文動作模式只有在Android 3.0或者更高版本可用且當可用時是首選的顯示上下文動作的技術。如果你的應用支持的版本低於3.0,那么你需要在這些設備中使用浮動的上下文菜單。效果如圖3-3所示:

 

圖 3-3 浮動上下文菜單截圖(左邊)和上下文動作條(右邊)

3.3.1創建浮動的上下文菜單

為了提供一個浮動的上下文菜單:

1. 通過調用resisterForContextMenu()來注冊上下文菜單相關的View。

如果你的Activity使用了ListView或者GridView且你想要每個選項都提供一個相同的上下文菜單,那么需要通過調用ListView或者GridView中的registerForContextMenu()為一個上下文菜單注冊所有的選項。

2. 在你的Activity或者Fragment實現onCreateContextMenu()的方法。

當注冊時接收到一個長點擊事件,那么系統將會調用你的onCreateContextMenu方法。這是你定義菜單項的地方,通常通過導入一個菜單資源。如代碼清單3-5所示:

@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);
}

 

代碼清單3-5

MenuInflater允許你從一個菜單資源導入上下文菜單。這種回調方法的參數包含了用戶選擇的View和提供關於被選項額外信息的ContextMenu.ContextMenuInfo對象。假如你的Activity有若干個提供不同上下文菜單的視圖,你需要使用這些參數來確定被導入的上下文菜單。

3. 實現onContextItemSelected()。

當用戶選擇一個菜單項時,系統調用這個方法則你可以執行相應的動作。如代碼清單3-6所示:

@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);
    }
}

 

代碼清單3-6

getItemId()方法為被選的菜單項查詢ID,這些ID是你在XML文件中使用android:id屬性分配給每個菜單項的。如在XML中定義一個菜單的章節中所講的。

當你成功的操作了一個菜單項,將返回true值,如果你不能操作菜單項,你需要通過基類來實現菜單項。如果你的Activity包含Fragment,那么Activity將首先接收到這個回調。當不能操作時通過調用基類,系統將會在每個Fragment中使用各自的回調方法過掉這個事件,一次一個(每個Fragment都已經被按順序添加了)直到返回true或者false已經返回了(默認Activity和Fragment實現時返回false,當不能操作時你總是需要調用基類)。

3.3.2使用上下文動作模式

上下文動作模式是系統實現的動作模式,重點是在執行上下文動作的用戶交互。當一個用戶通過選擇一個選項使這個模式啟用,那么上下文動作條將會出現在呈現用戶可執行的當前被選選項的屏幕的頂部。當這種模式被啟用,那么用戶可以選擇多個選項(如果你允許這樣的話),取消多個選項以及繼續在活動中導航(你允許的盡可能多的)。當用戶通過點擊返回按鈕取消選擇所有選項或者選擇動作條坐標的完成動作,則動作模式失效且上下文動作條消失。注意:上下文動作條沒有必要與動作條相關聯。它們是獨立運行的,即時上下文動作條顯示超過動作條的位置。如果你正在開發基於Android 3.0或者更高版本的應用,通常你需要使用上下文動作模式代替浮動上下文菜單來呈現上下文動作。

為提供上下文的視圖,通常你需要調用上下文的動作模式如以下兩個事件:

◆用戶在界面中執行長點擊。

◆用戶選擇一個復選框或者視圖中類似的UI組件。

如何使你的應用調用上下文動作模式且根據你的設計為每個動作定義行為。基本上有兩種設計:

◆    對於個別的任意視圖的上下文動作

◆    對於在ListView或者GridView的選項組的一些上下文動作(允許用戶選擇多個選項並執行它們所有的動作)。

接下來的部分是描述各個方案所需的設置。

3.3.3為個別View啟用上下文動作模式

假如僅僅當用戶選擇特殊視圖時你想要調用上下文動作模式,那么你應該:

◆實現ActionMode.Callback接口。在它的回調方法中,你可以為上下文動作條指定動作,相應在動作選項上點擊事件,以及為動作模式操作其他生命周期事件。

◆當你想要顯示一個動作條(例如當用戶長點擊視圖)時可以調用startActionMode()方法。

例如:

1. 實現ActionMode.Callback接口,如代碼清單3-7所示:

private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
     @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.context_menu, menu);
        return true;
    }
 
   
    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false;
    }
 
    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_share:
                shareCurrentItem();
                mode.finish(); 
                return true;
            default:
                return false;
        }
    }
 
    @Override
    public void onDestroyActionMode(ActionMode mode) {
        mActionMode = null;
    }
};

 

代碼清單3-7

請注意,這些回調事件幾乎和選項菜單回調一模一樣的,除了這些還可以通過與事件相關的ActionMode對象。你可以使用ActionMode APIs來使CAB各種變化,例如使用setTitle()和setSubtitle()來修改標題和子標題(所有被選中的選項都可用)。

同時也請注意上述的例子在當動作模式被注銷時設定了mActionMode變量為空。下一步,你將會看到它是如何初始化以及如何在你可用的Activity或Fragment中保存成員變量。

2. 當需要時調用startActionMode()去啟用上下文動作模式,例如相應一個視圖中的長點擊,如代碼清單3-8所示:

someView.setOnLongClickListener(new View.OnLongClickListener() {
    public boolean onLongClick(View view) {
        if (mActionMode != null) {
            return false;
        }
        mActionMode = getActivity().startActionMode(mActionModeCallback);
        view.setSelected(true);
        return true;
    }
});

 

代碼清單3-8

當你調用startActionMode(),系統返回ActionMode被創建。通過保存這個成員變量,你可以在相應其他事件時改變上下文動作條。在上述例子中,ActionMode是被用於確保ActionMode實例不會被重建,在它已經激活的情況下,且在動作模式開始的時候檢查成員是否為空。

3.3.4在ListView或者GridView中啟用一批上下文動作

如果在ListView或者GridView(或者另一個AbsListView的擴展類)中你有一個選項分類,且想要允許用戶去執行一批動作,你需要:

◆實現AbsListView.MultiChoiceModeListener接口且使用setMultiChoiceModeListener()把它設定給一個視圖組。在監聽回調的方法的時候,你可以為上下文動作條指定動作,在動作項中相應點擊事件,或者操作來自ActionMode.Callback接口的其他回調。

◆使用CHOICE_MODE_MULTIPLE_MODAL調用setChoiceMode()。

如代碼清單3-9所示:

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) {
    }
 
    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_delete:
                deleteSelectedItems();
                mode.finish();
                return true;
            default:
                return false;
        }
    }
 
    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.context, menu);
        return true;
    }
 
    @Override
    public void onDestroyActionMode(ActionMode mode) {
      
    }
 
    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
     
        return false;
    }
});

 

代碼清單3-9

就是這樣,現在當用戶通過長點擊選擇一個選項時,系統將會調用onCreateActionMode()方法且為指定的動作顯示一個上下文動作條。當上下文動作條可見時,用戶可以選擇附加的選項。

在上下文動作提供共同的動作選項的一些情況下,你可能想要添加一個復選框或者相似的允許用戶選擇的選項的UI組件,因為它們也許不能通過長點擊行為發現。當一個用戶選擇復選框時,你可以通過使用setItemChecked()為各自的選項列表設定選擇狀態來調用上下文動作模式。

3.4 創建彈出菜單

彈出菜單是一個形式上的菜單標記在View上面。它出現在定位的窗口之下,如果那里有空間的話,或者在其上面。它對以下這些是有用的:

◆    為關聯到特殊內容的動作提供一個溢出模式的菜單(例如Gmail的郵件頭部,如圖3-4所示)。

 

圖3-4 在Gmail應用里的彈出菜單,從右上角浮出。

注意:這是不同於會影響到所選內容的普通動作的上下文菜單。為了使動作能夠影響所選內容,使用上下文動作模式或者浮動上下文菜單。

◆提供一個命令句的第二部分(例如一個標記為"Add"的按鈕,使用不同"Add"選項可產生一個彈出菜單)。

◆提供一個類似不保留持續選項的Spinner的下拉菜單。

注意:彈出菜單在API 11或者更高的版本可用。

如果你在XML中定義你的菜單,這里介紹了你怎樣去顯示彈出菜單:

1. 使用其結構實例化一個彈出菜單,可以獲取當前應用的Context和被標記的菜單的View。

2. 使用 MenuInflater來inflate 你的菜單資源到通過PopupMenu.getMenu()返回的菜單對象中。在API level 14或以上版本,你能使用PopupMenu.inflate() 代替。

3. 調用PopupMenu.show()。

如代碼清單3-10所示,有一個按鈕的點擊事件:

<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" />

 

代碼清單3-10

在Activity中需要這么寫,如代碼清單3-11所示:

public void showPopup(View v) {
    PopupMenu popup = new PopupMenu(this, v);
    MenuInflater inflater = popup.getMenuInflater();
    inflater.inflate(R.menu.actions, popup.getMenu());
    popup.show();
}

 

代碼清單3-11

3.4.1處理單擊事件

當用戶選擇一個菜單項去執行一個動作時,你必須調用setOnMenuItemclickListener()實現PopupMenu.OnMenuItemClickListener接口且用PopupMenu來注冊它。當用戶選擇一個選項時,系統將在你的界面中調用onMenuItemClick()函數來回調。如代碼清單3-12所示:

public void showMenu(View v) {
    PopupMenu popup = new PopupMenu(this, v);
    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;
    }
}

 

代碼清單3-12

3.5 創建菜單組

菜單組是一個分享某些特征的菜單項集合,使用菜單組,你可以:

◆使用setGroupVisible()顯示或隱藏所有選項;

◆使用setGroupEnabled()讓所有選項有效或無效;

◆使用setGroupCheckable()指定是否所有選項可選。

在你的菜單資源或者使用add()方法指定的菜單組ID中,你可以在<group>元件里嵌套<item>元件來創建菜單組。這里有一個包含菜單組的菜單資源例子,如代碼清單3-13所示:

<?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-13

這些在組里的選項與第一個選項一樣的級別顯示——在菜單里的所有三個選項是同級別的。然而,你可以通過查詢組的ID地址和使用上面列出的方法來修改組里面兩個選項的特征。系統還從未分離過組選項。例如,假如你為每一個選項聲明android:showAsAction="ifRoom",那么他們將同時出現在動作條上或者動作溢出上。

3.5.1使用可選的菜單項

個菜單可以被當做選項開關的接口,獨立選項使用復選框,或者互相排斥的選項。組使用單選按鈕。如圖3-5顯示的是一個使用可選的單選按鈕的子菜單。

 

圖3-5 可選的子菜單的截圖。

注意:在圖標菜單里的菜單項(來自選項菜單)不能顯示復選框或者單選按鈕。假如你選擇讓圖標菜單里的選項可選,那么你需要在每次狀態改變時手動的改變圖標或者文字來表示選擇狀態。你可以在<item>元素使用android:checkable屬性來定義一個獨立菜單項的可選行為,或者在<group>元素里使用android:checkableBehavior屬性來為整個組定義。例如,這個菜單組里的所有選項使用單選按鈕且可選,如代碼清單3-14所示:

<?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>

 

代碼清單3-14

android:checkableBehavior屬性可設定為:

single:表示在菜單組中只有一個選項能被選中(單選按鈕)

all:表示所有選項都可被選(復選框)

none:表示沒有選項可選

你可以在<item>元素里使用android:checked屬性來定義選項的默認選擇狀態或者在代碼中使用setChecked()方法來改變狀態。當一個可選的項被選中,系統將調用選項各自的回調方法(例如onOptionsItemSelected())。在這里你必須設定復選框的狀態,因為復選框或者單選按鈕無法自動改變它們的狀態。你可以使用isChecked()查詢選項的當前狀態,以及使用setChecked()來設定它選中狀態。例如代碼清單3-15所示:

@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);
    }
}

 

代碼清單3-15

假如你不通過這種方式來設定選中狀態,那么選項的可視狀態(復選框或者單選按鈕)在用戶選中它時將不會改變。當你設定了狀態,activity將維持選項的選中狀態以至於當用戶較遲打開菜單,選中狀態你設定為可見。注意:可選菜單項是被擬用於每個會話基礎上的,且不能在應用銷毀后保留。假如你想為用戶保存應用設定信息,你需要使用Shared Preferences保存數據。

3.6 基於一個Intent添加菜單選項

一些時候你可能想要使用intent來載入一個Activity(無論這個Activity是在你的應用中或者在其他應用中)。當你知道你想要使用的intent且有一個可以開啟這個Intent的具體菜單項時,你可以在合適的選項被選中回調方法時使用startActivity()來開啟這個Intent(例如onOptionsItemSelected()回調)。然而,假如你不確定用戶的設備是否包含有處理這個Intent的應用,卻還添加了一個菜單項來調用它,這將導致生成一個無功能的菜單項,因為這個Intent可能無法在這個Activity中解決。為了解決這個問題,安卓系統可以允許你在設備發現發現了可以處理你的Intent的Activity時動態的添加菜單選項。以下基於可接受一個Intent的Activity的添加菜單方式:

1. 使用CATEGORY_ALTERNATIVE 和/或者 CATEGORY_SELECTED_ALTERNATIVE定義一個intent,可以添加其他任意需求。

2. 調用Menu.addIntentOptions()方法。安卓系統可以搜尋到任何能夠執行這個Intent的應用,且將它們添加到你的菜單中。

 

假如系統中沒有安裝可以滿足Intent的應用,那么將沒有菜單選項可以被添加。

注意:CATEGORY_SELECTED_ALTERNATIVE是被用來處理當前在屏幕上被選中的元素的。所以,它只能在采用onCreateContextMenu()創建菜單時使用。如代碼清單3-16所示:

 
@Override
public boolean onCreateOptionsMenu(Menu menu){
    super.onCreateOptionsMenu(menu);
    Intent intent = new Intent(null, dataUri);
    intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
    menu.addIntentOptions(
         R.id.intent_group,  // 將被添加到菜單組的item
         0,      // 唯一item ID (none)
         0,      // items順序 (none)
         this.getComponentName(),   // 當前 activity name
         null,   // 指定第一次放置的位置 (none)
         intent, // 根據我們的需求,傳入的intent
         0,      // 用來控制items的附加標志 (none)
         null);  // 關聯指定items的菜單items數組 (none)
 
    return true;
}

 

代碼清單3-16

為了讓每個Activity都能被找到,那么需要提供一個匹配已定義的Intent的容器、一個被添加進來的菜單項、使用在intent容器中類似菜單項名字的android:label的值,以及類似菜單項圖標的應用圖標。addIntentOptions()方法將返回被添加進來的選項的數量。注意:當你調用addIntentOptions(),它將覆蓋菜單組指定的所有菜單項。

3.6.1允許你的Activity添加到其他菜單

你可也可以為其他應用提供你的Activity中的服務,所以你的應用也可以被包含在其他應用的菜單中(反之亦可)。為了能夠被添加到其他應用得菜單中,通常你需要定義一個intent filter,但是必須要包含 CATEGORY_ALTERNATIVE 和/或者 CATEGORY_SELECTED_ALTERNATIVE 的intent filter category(類別)的值。例如代碼清單3-17所示:

<intent-filter label="@string/resize_image">
    ...
    <category android:name="android.intent.category.ALTERNATIVE" />
    <category android:name="android.intent.category.SELECTED_ALTERNATIVE" />
    ...
</intent-filter>

 

代碼清單3-17

 FAQ QQ群213821767


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM