從 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)建選項菜單
在選項菜單中驾中,你應(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)用欄。
你可以通過 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)建上下文菜單
上下文菜單提供了許多操作祥得,這些操作影響 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í)行以下操作:
通過調(diào)用
registerForContextMenu()
渠抹,注冊應(yīng)與上下文菜單關(guān)聯(lián)的 View 并將其傳遞給 View蝙昙。如果 Activity 使用 ListView 或 GridView 且你希望每個項目均提供相同的上下文菜單,請通過將 ListView 或 GridView 傳遞給registerForContextMenu()
梧却,為上下文菜單注冊所有項目奇颠。在 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ù)確定要擴充的上下文菜單剂陡。
- 實現(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 的添加順序),直到返回 true
或 false
為止屑墨。(Activity
和 android.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):
實現(xiàn)
ActionMode.Callback
接口乡小。在其回調(diào)方法中阔加,你既可以為上下文操作欄指定操作,又可以響應(yīng)操作項目的點擊事件满钟,還可以處理操作模式的其他生命周期事件掸哑。當需要顯示操作欄時(例如,用戶長按視圖)零远,請調(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 或片段中的成員變量有何作用。
- 調(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)建彈出菜單
PopupMenu 是錨定到 View 的模態(tài)菜單。如果空間足夠搂妻,它將顯示在定位視圖下方蒙保,否則顯示在其上方。它適用于:
- 為與特定內(nèi)容確切相關(guān)的操作提供溢出樣式菜單(例如欲主,Gmail 的電子郵件標頭邓厕,如圖 4 所示)。
注:這與上下文菜單不同岛蚤,后者通常用于影響所選內(nèi)容的操作邑狸。對于影響所選內(nèi)容的操作,請使用上下文操作模式或浮動上下文菜單涤妒。
提供命令語句的另一部分(例如单雾,標記為“添加”且使用不同的“添加”選項生成彈出菜單的按鈕)。
提供類似于
Spinner
且不保留永久選擇的下拉菜單她紫。
注:
PopupMenu
在 API 級別 11 及更高版本中可用硅堆。
如果使用 XML 定義菜單,則顯示彈出菜單的方法如下:
實例化
PopupMenu
及其構(gòu)造函數(shù)贿讹,該函數(shù)將提取當前應(yīng)用的 Context 以及菜單應(yīng)錨定到的 View渐逃。使用
MenuInflater
將菜單資源擴充到PopupMenu.getMenu()
返回的 Menu 對象中。調(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 使用可選中的菜單項
作為啟用/禁用選項的接口绍在,菜單非常實用门扇,既可針對獨立選項使用復(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í)行以下操作:
使用類別
CATEGORY_ALTERNATIVE
和/或CATEGORY_SELECTED_ALTERNATIVE
以及任何其他要求定義 Intent论颅。調(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)用示例鼻听,請參閱記事本示例代碼财著。