Android 菜單

Menus

從 Android 3.0(API 級別 11)開始狞山,Android 設(shè)備不再提供一個專用 “菜單” 按鈕。隨著這種改變漂问,Android 應(yīng)用擺脫對包含 6 個項目的傳統(tǒng)菜單面板的依賴,取而代之的是提供一個應(yīng)用欄(app bar)來呈現(xiàn)常見的用戶操作。

以下內(nèi)容介紹所有 Android 版本系統(tǒng)的三種基本菜單或操作呈現(xiàn)效果的創(chuàng)建方法:

  • 選項菜單和應(yīng)用欄

    選項菜單是某個 Activity 的主菜單項蚤假,供你放置對應(yīng)用產(chǎn)生全局影響的操作栏饮,如 “搜索”、“撰寫電子郵件” 和 “設(shè)置”磷仰。

  • 上下文菜單和上下文操作模式

    上下文菜單是用戶長按某一元素時出現(xiàn)的浮動菜單袍嬉。它提供的操作將影響所選內(nèi)容或上下文框架。

    上下文操作模式在屏幕頂部欄顯示影響所選內(nèi)容的操作項目灶平,并允許用戶選擇多項伺通。

  • 彈出菜單

    彈出菜單將以垂直列表形式顯示一系列項目,這些項目將錨定到調(diào)用該菜單的視圖中民逼。它特別適用于提供與特定內(nèi)容相關(guān)的大量操作泵殴,或者為命令的另一部分提供選項。彈出菜單中的操作不會直接影響對應(yīng)的內(nèi)容拼苍,而上下文操作則會影響笑诅。相反,彈出菜單適用于與你 Activity 中的內(nèi)容區(qū)域相關(guān)的擴展操作疮鲫。

一吆你、使用 XML 定義菜單

對于所有菜單類型,Android 提供了標準的 XML 格式來定義菜單項俊犯。你應(yīng)在 XML 菜單資源中定義菜單及其所有項妇多,而不是在 Activity 的代碼中構(gòu)建菜單。定義后燕侠,你可以在 Activity 或 Fragment 中擴充(inflate)菜單資源(將其作為 Menu 對象加載)者祖。

使用菜單資源是一種很好的做法,原因如下:

  • 更易于使用 XML 可視化菜單結(jié)構(gòu)

  • 將菜單內(nèi)容與應(yīng)用的行為代碼分離

  • 允許你利用應(yīng)用資源框架绢彤,為不同的平臺版本七问、屏幕尺寸和其他配置創(chuàng)建備用菜單配置

要定義菜單,請在項目 res/menu/ 目錄內(nèi)創(chuàng)建一個 XML 文件茫舶,并使用以下元素構(gòu)建菜單:

  • <menu>
    定義 Menu械巡,即菜單項的容器。<menu> 元素必須是該文件的根節(jié)點饶氏,并且能夠包含一個或多個 <item><group> 元素讥耗。

  • <item>
    創(chuàng)建 MenuItem,此元素表示菜單中的一項疹启,可能包含嵌套的 <menu> 元素古程,以便創(chuàng)建子菜單。

  • <group>
    <item> 元素的不可見容器(可選)喊崖。它支持你對菜單項進行分類挣磨,使其共享活動狀態(tài)和可見性等屬性菲宴。

以下是名為 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> 元素支持多個屬性,你可使用這些屬性定義項目的外觀和行為芋齿。上述菜單中的項目包括以下屬性:

  • android:id
    項目特有的資源 ID同欠,讓應(yīng)用能夠在用戶選擇項目時識別該項目。

  • android:icon
    引用一個要用作項目圖標的可繪制對象。

  • android:title
    引用一個要用作項目標題的字符串新博。

  • android:showAsAction
    指定此項應(yīng)作為操作項目顯示在應(yīng)用欄中的時間和方式。

這些是你應(yīng)使用的最重要屬性夕冲,但還有許多其他屬性锨咙。有關(guān)所有受支持屬性的信息,請參閱菜單資源文檔挤忙。

你可以通過以 <item> 子元素的形式添加 <menu> 元素霜威,向任何菜單(子菜單除外)中的某個菜單項添加子菜單。當應(yīng)用具有大量可按主題進行組織的功能時册烈,類似于 PC 應(yīng)用程序菜單欄中的菜單項(“文件”戈泼、“編輯”、“視圖” 等)赏僧,子菜單非常有用大猛。 例如:

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

要在 Activity 中使用菜單,你需要使用 MenuInflater.inflate() 擴充菜單資源(將 XML 資源轉(zhuǎn)換為可編程對象)淀零。

二挽绩、創(chuàng)建選項菜單

圖 1. Android 2.3 系統(tǒng)上瀏覽器中的選項菜單。

在選項菜單中驾中,你應(yīng)當包括與當前 Activity 上下文相關(guān)的操作和其他選項唉堪,如 “搜索”、“撰寫電子郵件” 和 “設(shè)置”肩民。

選項菜單中的項目在屏幕上的顯示位置取決于你開發(fā)的應(yīng)用所適用的 Android 版本:

  • 如果你開發(fā)的應(yīng)用適用于 Android 2.3.x(API 級別 10)或更低版本唠亚,則當用戶按“菜單”按鈕時,選項菜單的內(nèi)容會出現(xiàn)在屏幕底部此改,如圖 1 所示趾撵。打開時,第一個可見部分是圖標菜單共啃,其中包含多達 6 個菜單項占调。 如果菜單包括 6 個以上項目,則 Android 會將第六項和其余項目放入溢出菜單移剪。用戶可以通過選擇“更多”打開該菜單究珊。

  • 如果你開發(fā)的應(yīng)用適用于 Android 3.0(API 級別 11)及更高版本,則選項菜單中的項目將出現(xiàn)在應(yīng)用欄中纵苛。 默認情況下剿涮,系統(tǒng)會將所有項目均放入操作溢出菜單中言津。用戶可以使用應(yīng)用欄右側(cè)的操作溢出菜單圖標(或者,通過按設(shè)備“菜單”按鈕(如有))顯示操作溢出菜單取试。 要支持快速訪問重要操作悬槽,你可以將 android:showAsAction="ifRoom" 添加到對應(yīng)的 <item> 元素,從而將幾個項目提升到應(yīng)用欄中(請參閱圖 2)瞬浓。

如需了解有關(guān)操作項目和其他應(yīng)用欄行為的詳細信息初婆,請參閱添加應(yīng)用欄

圖 2. Honeycomb Gallery 應(yīng)用中的應(yīng)用欄猿棉,其中顯示了導航標簽和相機操作項目(以及操作溢出菜單按鈕)磅叛。

你可以通過 Activity 子類或 Fragment 子類為選項菜單聲明項目。如果你的 Activity 和 Fragment 均為選項菜單聲明項目萨赁,則這些項目將合并到 UI 中弊琴。系統(tǒng)將首先顯示 Activity 的項目,隨后按每個 Fragment 添加到 Activity 中的順序顯示各 Fragment 的項目杖爽。如有必要敲董,你可以使用 android:orderInCategory 屬性,對需要移動的每個 <item> 中的菜單項重新排序慰安。

要為 Activity 指定選項菜單臣缀,請重寫 onCreateOptionsMenu()(Fragment 會提供自己的 onCreateOptionsMenu() 回調(diào))。通過此方法泻帮,你可以將菜單資源(使用 XML 定義)擴充到回調(diào)中提供的 Menu 中精置。 例如:

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

此外,你還可以使用 add() 添加菜單項锣杂,并使用 findItem() 檢索項目脂倦,以便使用 MenuItem API 修改其屬性。

如果你開發(fā)的應(yīng)用適用于 Android 2.3.x 及更低版本元莫,則當用戶首次打開選項菜單時赖阻,系統(tǒng)會調(diào)用 onCreateOptionsMenu() 來創(chuàng)建該菜單。 如果你開發(fā)的應(yīng)用適用于 Android 3.0 及更高版本踱蠢,則系統(tǒng)將在啟動 Activity 時調(diào)用 onCreateOptionsMenu()火欧,以便向應(yīng)用欄顯示項目。

2.1 處理點擊事件

用戶從選項菜單中選擇項目(包括應(yīng)用欄中的操作項目)時茎截,系統(tǒng)將調(diào)用 Activity 的 onOptionsItemSelected() 方法苇侵。 此方法將傳遞所選的 MenuItem。你可以通過調(diào)用 getItemId() 方法來識別項目企锌,該方法將返回菜單項的唯一 ID(由菜單資源中的 android:id 屬性定義榆浓,或通過提供給 add() 方法的整型數(shù)定義)。 你可以將此 ID 與已知的菜單項匹配撕攒,以執(zhí)行適當?shù)牟僮鞫妇椤@纾?/p>

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

成功處理菜單項后烘浦,系統(tǒng)將返回 true。如果未處理菜單項萍鲸,則應(yīng)調(diào)用 onOptionsItemSelected() 的超類實現(xiàn)(默認實現(xiàn)將返回 false)闷叉。

如果 Activity 包括 Fragment,則系統(tǒng)將依次為 Activity 和每個 Fragment(按照每個 Fragment 的添加順序)調(diào)用 onOptionsItemSelected()脊阴,直到有一個返回結(jié)果為 true 或所有 Fragment 均調(diào)用完畢為止片习。

提示:Android 3.0 新增了一項功能,支持你在 XML 中使用 android:onClick 屬性為菜單項定義點擊行為蹬叭。該屬性的值必須是 Activity 使用菜單定義的方法的名稱。 該方法必須是公用的状知,且接受單個 MenuItem 參數(shù)秽五;當系統(tǒng)調(diào)用此方法時,它會傳遞所選的菜單項饥悴。如需了解詳細信息和示例坦喘,請參閱菜單資源文檔。

提示:如果應(yīng)用包含多個 Activity西设,且其中某些 Activity 提供相同的選項菜單瓣铣,則可考慮創(chuàng)建一個僅實現(xiàn) onCreateOptionsMenu()onOptionsItemSelected() 方法的 Activity。然后贷揽,為每個應(yīng)共享相同選項菜單的 Activity 擴展此類棠笑。 通過這種方式,你可以管理一個用于處理菜單操作的代碼集禽绪,且每個子級類均會繼承菜單行為蓖救。若要將菜單項添加到一個子級 Activity,請重寫該 Activity 中的 onCreateOptionsMenu()印屁。 調(diào)用 super.onCreateOptionsMenu(menu)循捺,以便創(chuàng)建原始菜單項,然后使用 menu.add() 添加新菜單項雄人。 此外从橘,你還可以替代各個菜單項的超類行為。

2.2 在運行時更改菜單項

系統(tǒng)調(diào)用 onCreateOptionsMenu() 后础钠,將保留你填充的 Menu 實例恰力。除非菜單由于某些原因而失效,否則不會再次調(diào)用 onCreateOptionsMenu()旗吁。但是牺勾,你僅應(yīng)使用 onCreateOptionsMenu() 來創(chuàng)建初始菜單狀態(tài),而不應(yīng)使用它在 Activity 生命周期中執(zhí)行任何更改阵漏。

如需根據(jù)在 Activity 生命周期中發(fā)生的事件修改選項菜單驻民,則可通過 onPrepareOptionsMenu() 方法執(zhí)行此操作翻具。此方法向你傳遞 Menu 對象(因為該對象目前存在),以便你能夠?qū)ζ溥M行修改回还,如添加裆泳、移除或禁用項目。(此外柠硕,fragment 也提供 onPrepareOptionsMenu() 回調(diào)工禾。)

在 Android 2.3.x 及更低版本中,每當用戶打開選項菜單時(按“菜單”按鈕)蝗柔,系統(tǒng)均會調(diào)用 onPrepareOptionsMenu()闻葵。

在 Android 3.0 及更高版本中,當菜單項顯示在應(yīng)用欄中時癣丧,選項菜單被視為始終處于打開狀態(tài)槽畔。 發(fā)生事件時,如果你要執(zhí)行菜單更新胁编,則必須調(diào)用 invalidateOptionsMenu() 來請求系統(tǒng)調(diào)用 onPrepareOptionsMenu()厢钧。

注:切勿根據(jù)目前處于焦點的 View 更改選項菜單中的項目。 處于觸摸模式(用戶未使用軌跡球或方向鍵)時嬉橙,視圖無法形成焦點早直,因此切勿根據(jù)焦點修改選項菜單中的項目。 若要為 View 提供上下文相關(guān)的菜單項市框,請使用上下文菜單霞扬。

三、創(chuàng)建上下文菜單

圖 3. 浮動上下文菜單(左)和上下文操作欄(右)的屏幕截圖枫振。

上下文菜單提供了許多操作祥得,這些操作影響 UI 中的特定項目或上下文框架。你可以為任何視圖提供上下文菜單蒋得,但這些菜單通常用于 ListView级及、GridView 或用戶可直接操作每個項目的其他視圖集合中的項目。

提供上下文操作的方法有兩種:

  • 使用浮動上下文菜單额衙。用戶長按(按滓埂)一個聲明支持上下文菜單的視圖時,菜單顯示為菜單項的浮動列表(類似于對話框)窍侧。 用戶一次可對一個項目執(zhí)行上下文操作县踢。

  • 使用上下文操作模式。此模式是 ActionMode 的系統(tǒng)實現(xiàn)伟件,它將在屏幕頂部顯示上下文操作欄硼啤,其中包括影響所選項的操作項目。當此模式處于活動狀態(tài)時斧账,用戶可以同時對多項執(zhí)行操作(如果應(yīng)用允許)谴返。

注:上下文操作模式可用于 Android 3.0(API 級別 11)及更高版本煞肾,是顯示上下文操作(如果可用)的首選方法。如果應(yīng)用支持低于 3.0 版本的系統(tǒng)嗓袱,則應(yīng)在這些設(shè)備上回退到浮動上下文菜單籍救。

3.1 創(chuàng)建浮動上下文菜單

要提供浮動上下文菜單,請執(zhí)行以下操作:

  1. 通過調(diào)用 registerForContextMenu()渠抹,注冊應(yīng)與上下文菜單關(guān)聯(lián)的 View 并將其傳遞給 View蝙昙。如果 Activity 使用 ListView 或 GridView 且你希望每個項目均提供相同的上下文菜單,請通過將 ListView 或 GridView 傳遞給 registerForContextMenu()梧却,為上下文菜單注冊所有項目奇颠。

  2. 在 Activity 或 Fragment 中實現(xiàn) onCreateContextMenu() 方法。
    當注冊后的視圖收到長按事件時放航,系統(tǒng)將調(diào)用你的 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);
}

MenuInflater 允許你通過菜單資源擴充上下文菜單葫辐∷衙蹋回調(diào)方法參數(shù)包括用戶所選的 View,以及一個提供有關(guān)所選項的附加信息的 ContextMenu.ContextMenuInfo 對象耿战。如果 Activity 有多個視圖蛋叼,每個視圖均提供不同的上下文菜單,則可使用這些參數(shù)確定要擴充的上下文菜單剂陡。

  1. 實現(xiàn) onContextItemSelected()狈涮。
    用戶選擇菜單項時,系統(tǒng)將調(diào)用此方法鸭栖,以便你能夠執(zhí)行適當?shù)牟僮鳌?例如:
@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);
    }
}

getItemId() 方法將查詢所選菜單項的 ID歌馍,你應(yīng)使用 android:id 屬性將此 ID 分配給 XML 中的每個菜單項,如使用 XML 定義菜單部分所示晕鹊。

成功處理菜單項后松却,系統(tǒng)將返回 true。如果未處理菜單項溅话,則應(yīng)將菜單項傳遞給超類實現(xiàn)晓锻。 如果 Activity 包括 Fragment,則 Activity 將先收到此回調(diào)飞几。通過在未處理的情況下調(diào)用超類砚哆,系統(tǒng)會將事件逐一傳遞給每個 Fragment 中相應(yīng)的回調(diào)方法(按照每個 Fragment 的添加順序),直到返回 truefalse 為止屑墨。(Activityandroid.app.Fragment 的默認實現(xiàn)返回 false躁锁,因此你始終應(yīng)在未處理的情況下調(diào)用超類纷铣。)

3.2 使用上下文操作模式

上下文操作模式是 ActionMode 的一種系統(tǒng)實現(xiàn),它將用戶交互的重點轉(zhuǎn)到執(zhí)行上下文操作上灿里。用戶通過選擇項目啟用此模式時关炼,屏幕頂部將出現(xiàn)一個“上下文操作欄”,顯示用戶可對當前所選項執(zhí)行的操作匣吊。 啟用此模式后儒拂,用戶可以選擇多個項目(若你允許)、取消選擇項目以及繼續(xù)在 Activity 內(nèi)導航(在你允許的最大范圍內(nèi))色鸳。 當用戶取消選擇所有項目社痛、按“返回”按鈕或選擇操作欄左側(cè)的“完成”操作時,該操作模式將會停用命雀,且上下文操作欄將會消失蒜哀。

注:上下文操作欄不一定與應(yīng)用欄相關(guān)聯(lián)。 盡管表面上看來上下文操作欄取代了應(yīng)用欄的位置吏砂,但事實上二者獨立運行撵儿。

對于提供上下文操作的視圖,當出現(xiàn)以下兩個事件(或之一)時狐血,你通常應(yīng)調(diào)用上下文操作模式:

  • 用戶長按視圖淀歇。

  • 用戶選中復(fù)選框或視圖內(nèi)的類似 UI 組件。

應(yīng)用如何調(diào)用上下文操作模式以及如何定義每個操作的行為匈织,具體取決于你的設(shè)計浪默。 設(shè)計基本上分為兩種:

  • 針對單個任意視圖的上下文操作。

  • 針對 ListView 或 GridView 中項目組的批處理上下文操作(允許用戶選擇多個項目并針對所有項目執(zhí)行操作)缀匕。

下文介紹每種場景所需的設(shè)置纳决。

為單個視圖啟用上下文操作模式

如果希望僅當用戶選擇特定視圖時才調(diào)用上下文操作模式,則應(yīng):

  1. 實現(xiàn) ActionMode.Callback 接口乡小。在其回調(diào)方法中阔加,你既可以為上下文操作欄指定操作,又可以響應(yīng)操作項目的點擊事件满钟,還可以處理操作模式的其他生命周期事件掸哑。

  2. 當需要顯示操作欄時(例如,用戶長按視圖)零远,請調(diào)用 startActionMode()苗分。
    例如:

實現(xiàn) ActionMode.Callback 接口:

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

請注意,這些事件回調(diào)與選項菜單的回調(diào)幾乎完全相同牵辣,只是其中每個回調(diào)還會傳遞與事件相關(guān)聯(lián)的 ActionMode 對象摔癣。你可以使用 ActionMode API 對 CAB 進行各種更改,例如:使用 setTitle()setSubtitle()(這對指示要選擇多少個項目非常有用)修改標題和副標題。

另請注意择浊,操作模式被銷毀時戴卜,上述示例會將 mActionMode 變量設(shè)置為 null。 在下一步中琢岩,你將了解如何初始化該變量投剥,以及保存 Activity 或片段中的成員變量有何作用。

  1. 調(diào)用 startActionMode() 以便適時啟用上下文操作模式担孔,例如:響應(yīng)對 View 的長按操作:
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;
    }
});

當你調(diào)用 startActionMode() 時江锨,系統(tǒng)將返回已創(chuàng)建的 ActionMode。通過將其保存在成員變量中糕篇,你可以更改上下文操作欄來響應(yīng)其他事件啄育。 在上述示例中, ActionMode 用于在啟動操作模式之前檢查成員是否為空拌消,以確保當 ActionMode 實例已激活時不再重建該實例挑豌。

在 ListView 或 GridView 中啟用批處理上下文操作

如果你在 ListView 或 GridView 中有一組項目(或 AbsListView 的其他擴展),且需要允許用戶執(zhí)行批處理操作墩崩,則應(yīng):

實現(xiàn) AbsListView.MultiChoiceModeListener 接口氓英,并使用 setMultiChoiceModeListener() 為視圖組設(shè)置該接口。在偵聽器的回調(diào)方法中鹦筹,你既可以為上下文操作欄指定操作铝阐,也可以響應(yīng)操作項目的點擊事件,還可以處理從 ActionMode.Callback 接口繼承的其他回調(diào)盛龄。
使用 CHOICE_MODE_MULTIPLE_MODAL 參數(shù)調(diào)用 setChoiceMode()饰迹。
例如:

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 invalidate() request
        return false;
    }
});

就這么簡單》际模現(xiàn)在余舶,當用戶通過長按選擇項目時,系統(tǒng)即會調(diào)用 onCreateActionMode() 方法锹淌,并顯示包含指定操作的上下文操作欄匿值。當上下文操作欄可見時,用戶可以選擇其他項目赂摆。

在某些情況下挟憔,如果上下文操作提供常用的操作項目,則你可能需要添加一個復(fù)選框或類似的 UI 元素來支持用戶選擇項目烟号,這是因為他們可能沒有發(fā)現(xiàn)長按行為绊谭。用戶選中該復(fù)選框時尊残,你可以通過使用 setItemChecked() 將相應(yīng)的列表項設(shè)置為選中狀態(tài)程拭,以此調(diào)用上下文操作模式。

四劳吠、創(chuàng)建彈出菜單

圖 4. Gmail 應(yīng)用中的彈出菜單,錨定到右上角的溢出按鈕宪赶。

PopupMenu 是錨定到 View 的模態(tài)菜單。如果空間足夠搂妻,它將顯示在定位視圖下方蒙保,否則顯示在其上方。它適用于:

  • 為與特定內(nèi)容確切相關(guān)的操作提供溢出樣式菜單(例如欲主,Gmail 的電子郵件標頭邓厕,如圖 4 所示)。

注:這與上下文菜單不同岛蚤,后者通常用于影響所選內(nèi)容的操作邑狸。對于影響所選內(nèi)容的操作,請使用上下文操作模式或浮動上下文菜單涤妒。

  • 提供命令語句的另一部分(例如单雾,標記為“添加”且使用不同的“添加”選項生成彈出菜單的按鈕)。

  • 提供類似于 Spinner 且不保留永久選擇的下拉菜單她紫。

注:PopupMenu 在 API 級別 11 及更高版本中可用硅堆。

如果使用 XML 定義菜單,則顯示彈出菜單的方法如下:

  1. 實例化 PopupMenu 及其構(gòu)造函數(shù)贿讹,該函數(shù)將提取當前應(yīng)用的 Context 以及菜單應(yīng)錨定到的 View渐逃。

  2. 使用 MenuInflater 將菜單資源擴充到 PopupMenu.getMenu() 返回的 Menu 對象中。

  3. 調(diào)用 PopupMenu.show()民褂。

例如茄菊,以下是一個使用 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" />

稍后,Activity 可按照如下方式顯示彈出菜單:

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 及更高版本中赊堪,你可以將兩行合并在一起面殖,使用 PopupMenu.inflate() 擴充菜單。

當用戶選擇項目或觸摸菜單以外的區(qū)域時哭廉,系統(tǒng)即會清除此菜單脊僚。 你可使用 PopupMenu.OnDismissListener 偵聽清除事件。

4.1 處理點擊事件

要在用戶選擇菜單項時執(zhí)行操作遵绰,你必須實現(xiàn) PopupMenu.OnMenuItemClickListener 接口辽幌,并通過調(diào)用 setOnMenuItemclickListener() 將其注冊到 PopupMenu。 用戶選擇項目時椿访,系統(tǒng)會在接口中調(diào)用 onMenuItemClick() 回調(diào)乌企。

例如:

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

五、創(chuàng)建菜單組

菜單組是指一系列具有某些共同特征的菜單項成玫。通過菜單組加酵,你可以:

  • 使用 setGroupVisible() 顯示或隱藏所有項目

  • 使用 setGroupEnabled() 啟用或禁用所有項目

  • 使用 setGroupCheckable() 指定所有項目是否可選中

通過將 <item> 元素嵌套在菜單資源中的 <group> 元素內(nèi)端辱,或者通過使用 add() 方法指定組 ID,你可以創(chuàng)建組虽画。

以下是包含組的菜單資源示例:

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

組中的項目出現(xiàn)在與第一項相同的級別舞蔽,即:菜單中的所有三項均為同級。 但是码撰,你可以通過引用組 ID 并使用上面列出的方法渗柿,修改組中兩項的特征。此外脖岛,系統(tǒng)也絕不會分離已分組的項目朵栖。 例如,如果為每個項目聲明 android:showAsAction="ifRoom"柴梆,則它們會同時顯示在操作欄或操作溢出菜單中陨溅。

5.1 使用可選中的菜單項

圖 5. 含可選中項目的子菜單的屏幕截圖。

作為啟用/禁用選項的接口绍在,菜單非常實用门扇,既可針對獨立選項使用復(fù)選框,也可針對互斥選項組使用單選按鈕偿渡。 圖 5 顯示了一個子菜單臼寄,其中的項目可使用單選按鈕選中。

注:“圖標菜單(Icon Menu)”(在選項菜單中)的菜單項無法顯示復(fù)選框或單選按鈕溜宽。 如果你選擇使“圖標菜單”中的項目可選中吉拳,則必須在選中狀態(tài)每次發(fā)生變化時交換圖標和/或文本,手動指出該狀態(tài)适揉。

你可以使用 <item> 元素中的 android:checkable 屬性為各個菜單項定義可選中的行為留攒,或者使用 <group> 元素中的 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>

android:checkableBehavior 屬性接受以下任一選項:

  • single
    組中只有一個項目可以選中(單選按鈕)

  • all
    所有項目均可選中(復(fù)選框)

  • none
    所有項目均無法選中

你可以使用 <item> 元素中的 android:checked 屬性將默認的選中狀態(tài)應(yīng)用于項目炼邀,并可使用 setChecked() 方法在代碼中更改此默認狀態(tài)。

選擇可選中項目后吃沪,系統(tǒng)將調(diào)用所選項目的相應(yīng)回調(diào)方法(例如汤善,onOptionsItemSelected())什猖。 此時票彪,你必須設(shè)置復(fù)選框的狀態(tài),因為復(fù)選框或單選按鈕不會自動更改其狀態(tài)不狮。 你可以使用 isChecked() 查詢項目的當前狀態(tài)(正如用戶選擇該項目之前一樣)降铸,然后使用 setChecked() 設(shè)置選中狀態(tài)。例如:

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

如果未通過這種方式設(shè)置選中狀態(tài)摇零,則項目的可見狀態(tài)(復(fù)選框或單選按鈕)不會因為用戶選擇它而發(fā)生變化推掸。 如果已設(shè)置該狀態(tài),則 Activity 會保留項目的選中狀態(tài)。這樣一來谅畅,當用戶稍后打開菜單時登渣,你設(shè)置的選中狀態(tài)將會可見。

注:可選中菜單項的使用往往因會話而異毡泻,且在應(yīng)用銷毀后不予保存胜茧。 如果你想為用戶保存某些應(yīng)用設(shè)置,則應(yīng)使用共享首選項存儲數(shù)據(jù)仇味。

六呻顽、添加基于 Intent 的菜單項

有時,你希望菜單項通過使用 Intent 啟動 Activity(無論該 Activity 是位于你的應(yīng)用還是其他應(yīng)用中)丹墨。如果你知道自己要使用的 Intent廊遍,且具有啟動 Intent 的特定菜單項,則可在相應(yīng)的 on-item-selected 回調(diào)方法(例如贩挣,onOptionsItemSelected() 回調(diào))期間使用 startActivity() 執(zhí)行 Intent喉前。

但是,如果不確定用戶的設(shè)備是否包含可處理 Intent 的應(yīng)用王财,則添加調(diào)用 Intent 的菜單項可能會導致該菜單項無法正常工作被饿,這是因為 Intent 可能無法解析為 Activity。為了解決這一問題搪搏,當 Android 在設(shè)備上找到可處理 Intent 的 Activity 時狭握,則允許你向菜單動態(tài)添加菜單項。

要根據(jù)接受 Intent 的可用 Activity 添加菜單項疯溺,請執(zhí)行以下操作:

  1. 使用類別 CATEGORY_ALTERNATIVE 和/或 CATEGORY_SELECTED_ALTERNATIVE 以及任何其他要求定義 Intent论颅。

  2. 調(diào)用 Menu.addIntentOptions()。Android 隨后即會搜索能夠執(zhí)行 Intent 的所有應(yīng)用囱嫩,并將其添加到菜單中恃疯。

如果未安裝可處理 Intent 的應(yīng)用,則不會添加任何菜單項墨闲。

注:CATEGORY_SELECTED_ALTERNATIVE 用于處理屏幕上當前所選的元素今妄。因此,只有在 onCreateContextMenu() 中創(chuàng)建菜單時鸳碧,才能使用它盾鳞。

例如:

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

如果發(fā)現(xiàn) Activity 提供的 Intent 過濾器與定義的 Intent 匹配,則會添加菜單項瞻离,并使用 Intent 過濾器 android:label 中的值作為菜單項標題腾仅,使用應(yīng)用圖標作為菜單項圖標。addIntentOptions() 方法將返回已添加的菜單項數(shù)量套利。

注:調(diào)用 addIntentOptions() 方法時推励,它將使用第一個參數(shù)中指定的菜單組替代所有菜單項鹤耍。

6.1 允許將 Activity 添加到其他菜單中

此外,你還可以為其他應(yīng)用提供你的 Activity 服務(wù)验辞,以便你的應(yīng)用能夠包含在其他應(yīng)用的菜單中(與上述角色相反)稿黄。

要包含在其他應(yīng)用菜單中,你需要按常規(guī)方式定義 Intent 過濾器跌造,但請確保為 Intent 過濾器類別添加 CATEGORY_ALTERNATIVE 和/或 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>

請仔細閱讀 Intent 和 Intent 過濾器文檔中更多有關(guān)編寫 Intent 過濾器的內(nèi)容。

有關(guān)使用此方法的應(yīng)用示例鼻听,請參閱記事本示例代碼财著。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市撑碴,隨后出現(xiàn)的幾起案子撑教,更是在濱河造成了極大的恐慌,老刑警劉巖醉拓,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伟姐,死亡現(xiàn)場離奇詭異,居然都是意外死亡亿卤,警方通過查閱死者的電腦和手機愤兵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來排吴,“玉大人秆乳,你說我怎么就攤上這事∽炅ǎ” “怎么了屹堰?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長街氢。 經(jīng)常有香客問我扯键,道長,這世上最難降的妖魔是什么珊肃? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任荣刑,我火速辦了婚禮,結(jié)果婚禮上伦乔,老公的妹妹穿的比我還像新娘厉亏。我一直安慰自己,他們只是感情好评矩,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布叶堆。 她就那樣靜靜地躺著阱飘,像睡著了一般斥杜。 火紅的嫁衣襯著肌膚如雪虱颗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天蔗喂,我揣著相機與錄音忘渔,去河邊找鬼。 笑死缰儿,一個胖子當著我的面吹牛畦粮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乖阵,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼宣赔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瞪浸?” 一聲冷哼從身側(cè)響起儒将,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎对蒲,沒想到半個月后钩蚊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡蹈矮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年砰逻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泛鸟。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡蝠咆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出北滥,到底是詐尸還是另有隱情勺美,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布碑韵,位于F島的核電站赡茸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏祝闻。R本人自食惡果不足惜占卧,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望联喘。 院中可真熱鬧华蜒,春花似錦、人聲如沸豁遭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓖谢。三九已至捂蕴,卻和暖如春譬涡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背啥辨。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工涡匀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溉知。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓陨瘩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親级乍。 傳聞我的和親對象是個殘疾皇子舌劳,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容

  • http://developer.android.youdaxue.com/guide/topics/ui/men...
    acc8226閱讀 1,192評論 0 3
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,426評論 0 17
  • 《小草》 ——瘦桶 每一縷晚風 都在我身上 劃出自己的旋律 也為我?guī)磉h方的故事 還沒來得及向春天道別 ...
    瘦桶閱讀 338評論 0 61
  • 最近看了一部劇玫荣,有點癡迷其中的劇情蒿囤。 以下是我整理的傅恒的語錄,請忽略我的畫崇决。 1材诽、魏瓔珞,你是個恩怨分明的人恒傻,是...
    萍欄閱讀 809評論 0 0
  • 一脸侥、koa-router 二、koa-bodyparser 獲取post數(shù)據(jù) 三盈厘、koa-static 配置靜態(tài)文...
    R_X閱讀 2,110評論 0 1