選單是一種適用於多種應用程式的常見使用者介面元件。為了提供熟悉且一致的使用者體驗,您應在活動中使用 Menu
API 為使用者呈現動作和其他選項。
從 Android 3.0(API 級別 11)開始,搭載 Android 的裝置不再需要提供專用的選單按鈕。在這項改變下,Android 應用程式不應再使用傳統的 6 項式選單面板,應改為使用一個應用程式列來顯示常見的使用者操作。
儘管部分選單項目的設計和使用者體驗有所改變,但用來定義一組操作和選項的語意仍是以 Menu
API 為基礎。本指南說明如何在所有版本的 Android 上建立三種基本選單類型或操作的呈現:
- 選項選單和應用程式列
- 選項選單是一項活動的選單項目的主集合。在這裡,您應該放置會對應用程式造成全域影響的操作,例如「搜尋」、「撰寫電子郵件」和「設定」。
請參閱建立選項選單一節。
- 內容選單及關聯動作模式
- 內容選單是一種浮動式選單,會在使用者長按元素時顯示。它提供的一些操作會影響所選的內容或內容畫面。
關聯動作模式會在螢幕上方長條中顯示會影響所選內容的操作項目,並允許使用者選取多個選項。
請參閱「建立關聯選單」一節。
- 彈出式選單
- 彈出式選單會以垂直清單的方式顯示一列項目,該清單會固定在呼叫出選單的檢視畫面中。它有助於提供與特定內容相關的操作溢位,或為一項指令提供第二部分的選項。在彈出式選單中的操作不應直接影響相對應的內容,這就是關聯動作的目的。相反地,彈出式選單適合在您的活動中,用來擴充與內容區域相關的操作。
請參閱建立彈出式選單一節。
以 XML 定義選單
對於所有類型的選單,Android 都提供了標準的 XML 格式來定義選單項目。
您不應在活動的程式碼中建立選單,而是應於 XML 選單資源中定義選單及其所有項目。接著即可在活動或片段中加載選單資源(以 Menu
物件載入)。
使用選單資源是好的做法,原因在於:
- 在 XML 中可以更簡單明暸地看到選單結構。
- 它將選單內容與應用程式的行為程式碼區隔開來。
- 透過這個 應用程式資源架構,可為不同的平台版本、螢幕大小和其他設定,建立不同的選單設定。
如要定義選單,請在專案的 res/menu/
目錄中建立 XML 檔案,然後以下列元素建立選單:
<menu>
- 定義一個
Menu
,這是選單項目使用的容器。<menu>
元素必須是檔案的根節點,且可包含一或多個<item>
和<group>
元素。 <item>
- 建立一個
MenuItem
,用來表示選單中的單一項目。此元素可以包含巢狀結構的<menu>
元素,用來建立子選單。 <group>
- 用於
<item>
元素的選擇性隱藏容器。可以用來對選單項目進行分類,使其可以共用諸多屬性,例如活動狀態及瀏覽權限等。詳情請參閱建立選單群組一節。
以下是名為 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,可讓使用者在選取時,讓應用程式識別出該項目。
android:icon
- 可繪項目的參照,用來作為項目的圖示。
android:title
- 字串的參照,用來作為項目標題。
android:showAsAction
- 指定此項目應在應用程式列顯示為動作項目的時間和方式。
這些是您應該使用的最重要屬性,不過還有更多屬性可用。 所有支援屬性的相關資訊,請參閱選單資源文件。
您可以新增 <menu>
元素做為 <item>
的子項,即可在任何選單中為項目新增子選單。如果應用程式有許多功能可以依主題分類,就如同電腦應用程式選單列中的各個項目(「檔案」、「編輯」、「檢視」等),就可以用到子選單。例如:
<?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>
若要在活動中使用選單,必須使用 MenuInflater.inflate()
加載選單資源(將 XML 資源轉換為可編寫程式的物件)。以下章節將為您介紹如何為每種選單類型加載選單。
建立選項選單

圖 1. 瀏覽器中的選項選單。
選項選單應包含與目前活動情境相關的操作和其他選項,例如「搜尋」、「撰寫電子郵件」及「設定」。
畫面中顯示選項選單的項目的位置,取決於您開發應用程式的版本:
- 如果您是在 Android 2.3.x(API 級別 10)或以下版本開發應用程式,則當使用者按下選單按鈕時,選項選單中的內容會出現在螢幕頂端(如圖 1 所示)。開啟時,首先顯示的部分是圖示選單,最多可顯示六個選單項目。如果選單的項目多於六個,Android 會將第六個與其餘的項目放置在溢位選單中,使用者只需選擇更多即可開啟該選單。
- 如果您是在 Android 3.0(API 級別 11)以上版本開發應用程式,選項選單中的項目會顯示在應用程式列。在預設的情況下,系統會將所有項目都放在動作溢位中,使用者可以透過應用程式列右側的動作溢位圖示查看(或是如果有的話,按下裝置的選單按鈕)。若要能夠快速存取重要動作,可以在對應的
<item>
元素中加入android:showAsAction="ifRoom"
,讓一些項目升級顯示在應用程式列中(見圖 2)。若要進一步瞭解操作項目及其他應用程式列的行為,請參閱新增應用程式列訓練課程。

圖 2. Google 試算表應用程式, 顯示了多個按鈕,包括動作溢位按鈕在內。
您可以從 Activity
子類別或 Fragment
子類別中宣告選項選單的項目。如果您的活動和片段都宣告了選項選單的項目,使用者介面會將這些項目合併。活動的項目會先顯示,接著依照每個片段被加入活動的順序顯示各個片段的項目。如有需要,您可以在每個需要移動的 <item>
中使用 android:orderInCategory
屬性重新排序選單項目。
若要指定活動的選項選單,請覆寫 onCreateOptionsMenu()
(由片段自行提供其 onCreateOptionsMenu()
回呼)。使用此方法時,您可以將選單資源(以 XML 定義)加載至回呼提供的 Menu
中。例如:
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { val inflater: MenuInflater = menuInflater inflater.inflate(R.menu.game_menu, menu) return true }
Java
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.game_menu, menu); return true; }
您也可以利用 add()
新增選單項目,並利用 findItem()
擷取項目來修改其與 MenuItem
API 關聯的屬性。
如果您是針對 Android 2.3.x 及更低版本開發應用程式,系統會在使用者首次打開選單時呼叫 onCreateOptionsMenu()
以建立選項選單。如果您是為 Android 3.0 及以上版本開發,系統會在啟動活動時呼叫 onCreateOptionsMenu()
,讓項目顯示在應用程式列中。
處理點擊事件
當使用者從選項選單中選取項目(包括應用程式列中的動作項目)時,系統會呼叫活動的 onOptionsItemSelected()
方法。此方法會傳遞所選的 MenuItem
。您可以藉由呼叫 getItemId()
確認該項目,這會回傳選單項目的專屬 ID(由選單資源中的 android:id
屬性所定義,或是向 add()
方法指定一個整數)。您可以將此 ID 與已知的選單項目進行比對,以執行適當的操作。例如:
Kotlin
override fun onOptionsItemSelected(item: MenuItem): Boolean { // Handle item selection return when (item.itemId) { R.id.new_game -> { newGame() true } R.id.help -> { showHelp() true } else -> super.onOptionsItemSelected(item) } }
Java
@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); } }
成功處理選單項目後,將 true
傳回。如果您不處理選單項目,則應呼叫 onOptionsItemSelected()
父類別執行(預設執行結果會回傳否)。
如果活動中含有片段,系統會先針對活動呼叫 onOptionsItemSelected()
,接著針對每個片段呼叫(依每個片段加入的順序),直到一個呼叫回傳 true
或所有片段均被呼叫為止。
提示:Android 3.0 新增了一項功能,可以使用 android:onClick
屬性以 XML 定義選單項目的點擊行為。屬性值必須是方法的名稱,該名稱由使用選單的活動定義。此方法必須公開且接受單一的 MenuItem
參數 — 當系統呼叫此方法時,它會傳遞已選取的選單項目。如需詳細資訊和範例,請參閱選單資源文件。
提示:如果您的應用程式具有多項活動,而其中部分使用的是相同的選項選單,請考慮建立一個僅執行 onCreateOptionsMenu()
和 onOptionsItemSelected()
方法的活動。接著將這個類別擴充給每個應共用相同選項選單的活動使用。這麼一來,您就可以管理一組用來處理選單操作的程式碼,而每個子類別都可繼承這個選單行為。如果您想為其中一個子活動新增選單項目,請在該活動中覆寫 onCreateOptionsMenu()
。呼叫 super.onCreateOptionsMenu(menu)
即可建立原始選單項目,接著以 menu.add()
新增選單項目。您也可以為個別的選單項目覆寫父類別的行為。
在執行階段變更選單項目
系統呼叫 onCreateOptionsMenu()
後,會保留您填入的 Menu
執行個體而不會再次呼叫 onCreateOptionsMenu()
,除非該選單因特定原因變為無效。不過,建議您只將 onCreateOptionsMenu()
用於建立初始選單狀態,不要在活動生命週期內進行變更。
若想要依據活動生命週期中發生的事件修改選項選單,可以使用 onPrepareOptionsMenu()
方法。此方法會向您傳遞目前存在的 Menu
物件,因此您可以加以修改,例如新增、移除或停用項目。(片段也會提供 onPrepareOptionsMenu()
回呼)。
在 Android 2.3.x 及更低的版本中,使用者每次開啟選項選單(按下選單按鈕)時,系統便會呼叫 onPrepareOptionsMenu()
。
在 Android 3.0 以上的版本中,當應用程式列顯示選單項目時,選項選單會一律開啟。當事件發生且您想要更新選單時,您必須呼叫 invalidateOptionsMenu()
以要求系統呼叫 onPrepareOptionsMenu()
。
注意:請勿根據目前焦點所在的 View
變更選項選單中的項目。在輕觸模式中(當使用者未使用軌跡球或 D-pad 時)檢視畫面無法取得焦點,因此,因此您不應以焦點做為修改選項選單中項目的基礎。若要提供依 View
內容而定的選單項目,請使用內容選單。
建立內容選單

圖 3. 浮動內容選單(左)和關聯動作列(右)的螢幕截圖。
內容選單可提供會影響使用者介面中特定項目或內容畫面的操作。您可以為任何檢視畫面提供內容選單,但它們通常用於 ListView
、GridView
中的項目,或其他使用者可以直接對各個項目進行操作的檢視畫面集合。
提供內容關聯操作的方法有兩種:
- 在浮動內容選單中。當使用者在檢視畫面上長按(按住),且該檢視畫面宣告支援內容選單時,選單就會以浮動式清單的方式顯示選單項目清單(類似於一個對話方塊)。使用者一次可以對一個項目執行內容關聯操作。
- 在關聯動作模式中。此模式是系統執行
ActionMode
的作法,會在畫面頂端顯示關聯動作列,其中包含會影響所選項目的操作項目。啟用此模式時,使用者一次可對多個項目執行一項操作(如果應用程式允許)。
注意:關聯動作模式適用於 Android 3.0(API 級別 11)及以上版本,且可以的話,建議您盡可能使用此技術來顯示關聯動作。如果您的應用程式支援 3.0 以下版本,針對這些裝置您應該回到使用浮動內容選單。
建立浮動內容選單
如何提供浮動內容選單:
- 呼叫
registerForContextMenu()
並將其傳遞到View
,以註冊與內容選單相關的View
。如果您的活動使用
ListView
或GridView
且您希望每個項目都提供相同的內容選單,那麼請將ListView
或GridView
傳遞到registerForContextMenu()
以註冊內容選單的所有項目。 - 在您的
Activity
或Fragment
中執行onCreateContextMenu()
方法。當註冊的檢視畫面收到長按事件時,系統會呼叫
onCreateContextMenu()
方法。您可以在此定義選單項目,作法通常為加載一個選單資源。舉例來說:Kotlin
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo) { super.onCreateContextMenu(menu, v, menuInfo) val inflater: MenuInflater = menuInflater inflater.inflate(R.menu.context_menu, menu) }
Java
@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
從選單資源中加載內容選單。回呼方法參數包括使用者選用的View
,以及可提供與選取項目相關額外資訊的ContextMenu.ContextMenuInfo
物件。如果活動有多個檢視畫面,且每個檢視畫面提供不同的內容選單,您可以利用這些參數來判斷要加載哪些內容選單。 - 實作
onContextItemSelected()
。當使用者選取選單項目時,系統會呼叫此方法讓您執行適當的操作。例如:
Kotlin
override fun onContextItemSelected(item: MenuItem): Boolean { val info = item.menuInfo as AdapterView.AdapterContextMenuInfo return when (item.itemId) { R.id.edit -> { editNote(info.id) true } R.id.delete -> { deleteNote(info.id) true } else -> super.onContextItemSelected(item) } }
Java
@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,您應該使用android:id
屬性以 XML 為每個選單項目進行指派,作法如以 XML 定義選單一節所述。成功處理選單項目後,將
true
傳回。如果您不處理選單項目,則應將選單項目傳至父類別進行實作。如果您的活動含有片段,活動會先收到此回呼。在未處理的情況下呼叫父類別時,系統會把此事件傳遞到每個片段中相應的回呼方法,每次傳遞一個(依每個片段的新增順序),直至傳回true
或false
為止。(Activity
和android.app.Fragment
的預設作法會傳回false
,因此您必須在未處理時呼叫父類別。)
使用關聯動作模式
關聯動作模式是 ActionMode
的系統實作,著重於將使用者互動轉為執行關聯操作。當使用者選取某個項目啟用此模式時,螢幕頂端會出現關聯動作列,以顯示使用者可以對目前選取項目執行的操作。啟用此模式後,使用者就可以選取多個項目(如果您允許的話)、取消選取項目,以及繼續在活動中瀏覽(視您允許的情況而定)。當使用者取消選取所有項目、按下「返回」按鈕或選取列左側的完成動作時,操作模式即會停用,關聯動作列會消失。
注意:關聯動作列不需與應用程式列有所關聯。雖然關聯動作列看起來會出現在應用程式列的位置,但它們是獨立作業的。
針對提供內容關聯操作的檢視畫面,通常應在兩個事件之一(或兩者)上叫用關聯動作模式:
- 使用者長按檢視畫面。
- 使用者在檢視畫面中選取核取方塊或類似的 UI 元件。
您的設計決定了應用程式如何叫用關聯動作模式,並定義了每個操作的行為。基本上有兩種設計:
以下章節介紹了各個情境所需的設定。
為個別檢視畫面啟用關聯動作模式
如果只想在使用者選取特定檢視畫面時叫用關聯動作模式,您應採取下列做法:
- 執行
ActionMode.Callback
介面。在回呼方法中,您可以指定關聯動作列的操作、回應操作項目的點擊事件,以及為操作模式處理其他生命週期事件。 - 若要顯示列(例如在使用者長按檢視畫面時),請呼叫
startActionMode()
。
例如:
- 執行
ActionMode.Callback
介面:Kotlin
private val actionModeCallback = object : ActionMode.Callback { // Called when the action mode is created; startActionMode() was called override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { // Inflate a menu resource providing context menu items val inflater: MenuInflater = mode.menuInflater 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 fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { return false // Return false if nothing is done } // Called when the user selects a contextual menu item override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { return when (item.itemId) { R.id.menu_share -> { shareCurrentItem() mode.finish() // Action picked, so close the CAB true } else -> false } } // Called when the user exits the action mode override fun onDestroyActionMode(mode: ActionMode) { actionMode = null } }
Java
private ActionMode.Callback actionModeCallback = 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) { actionMode = null; } };
請注意,這些事件回呼與選項選單中的回呼幾乎相同,唯每個回呼也會傳送與事件相關的
ActionMode
物件。您可以使用ActionMode
API 對 CAB 進行多項變更,例如利用setTitle()
和setSubtitle()
修改標題及子標題(可用來指出已選取的項目數量)。另外也請注意,上述範例在刪除操作模式時,會將
actionMode
變數設為null
。在下一步中,您將瞭解其初始化的方式,以及在活動或片段中儲存成員變數的好處。 - 視情況呼叫
startActionMode()
以啟用關聯動作模式,例如對長按View
做出回應:Kotlin
someView.setOnLongClickListener { view -> // Called when the user long-clicks on someView when (actionMode) { null -> { // Start the CAB using the ActionMode.Callback defined above actionMode = activity?.startActionMode(actionModeCallback) view.isSelected = true true } else -> false } }
Java
someView.setOnLongClickListener(new View.OnLongClickListener() { // Called when the user long-clicks on someView public boolean onLongClick(View view) { if (actionMode != null) { return false; } // Start the CAB using the ActionMode.Callback defined above actionMode = getActivity().startActionMode(actionModeCallback); view.setSelected(true); return true; } });
當您呼叫
startActionMode()
時,系統會傳回建立的ActionMode
。將此項目儲存至成員變數中,即可變更關聯動作列以回應其他事件。在上述的範例中,ActionMode
是用來確保在活動期間不會重新建立ActionMode
執行個體,方法是先檢查成員的值是否為空值,接著再啟用操作模式。
在 ListView 或 GridView 中啟用批次關聯動作
如果您在 ListView
或 GridView
(或其他 AbsListView
的擴充)中有某項目集合,而且想讓使用者執行批次操作,則應採取以下做法:
- 實作
AbsListView.MultiChoiceModeListener
介面,並利用setMultiChoiceModeListener()
將其設定給檢視區塊群組使用。在事件監聽器的回呼方法中,您可以指定關聯動作列的操作、回應操作項目的點擊事件,以及處理其他從ActionMode.Callback
介面繼承而來的回呼。 - 使用
CHOICE_MODE_MULTIPLE_MODAL
引數呼叫setChoiceMode()
。
例如:
Kotlin
val listView: ListView = getListView() with(listView) { choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL setMultiChoiceModeListener(object : AbsListView.MultiChoiceModeListener { override fun onItemCheckedStateChanged(mode: ActionMode, position: Int, id: Long, checked: Boolean) { // Here you can do something when items are selected/de-selected, // such as update the title in the CAB } override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { // Respond to clicks on the actions in the CAB return when (item.itemId) { R.id.menu_delete -> { deleteSelectedItems() mode.finish() // Action picked, so close the CAB true } else -> false } } override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean { // Inflate the menu for the CAB val menuInflater: MenuInflater = mode.menuInflater menuInflater.inflate(R.menu.context, menu) return true } override fun onDestroyActionMode(mode: ActionMode) { // Here you can make any necessary updates to the activity when // the CAB is removed. By default, selected items are deselected/unchecked. } override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean { // Here you can perform updates to the CAB due to // an <code><a href="/reference/android/view/ActionMode.html#invalidate()">invalidate()</a></code> request return false } }) }
Java
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 <code><a href="/reference/android/view/ActionMode.html#invalidate()">invalidate()</a></code> request return false; } });
大功告成!當使用者以長按的方式選取一個項目時,系統會呼叫 onCreateActionMode()
方法,並顯示含有指定操作的關聯動作列。顯示出關聯動作列後,使用者即可以選取其他項目。
在某些情況下,關聯操作會提供常用的操作項目,您可能會想要新增核取方塊或類似的 UI 元素,讓使用者可以選取項目,因為他們可能不會發現長按的行為。當使用者選取核取方塊時,您可以叫用關聯動作模式,方法是透過 setItemChecked()
將對應的清單項目設定為勾選狀態。
建立彈出式選單

圖 4. Gmail 應用程式的彈出式選單,其固定在右上方的溢位按鈕上。
PopupMenu
是固定在 View
上的模式選單。如果有空間,它或顯示在錨定檢視畫面下方,或是在檢視畫面上方。這適用於:
- 為與特定內容(例如圖 4 中顯示的 Gmail 電子郵件標頭)相關的操作提供溢位樣式選單。
- 提供指令句的第二部分(例如標示「新增」的按鈕,可產生包含不同「新增」選項的彈出式選單)。
- 提供類似
Spinner
而不會保留永久選項的下拉式選單。
注意: PopupMenu
適用於 API 級別 11 及以上版本。
如果您以 XML 定義選單,您可以按照下列步驟顯示彈出式選單:
- 利用其建構函式將
PopupMenu
執行個體化,此操作會將目前應用程式的Context
和View
帶到選單應該錨定的地方。 - 使用
MenuInflater
將選單資源加載至PopupMenu.getMenu()
傳回的Menu
物件。 - 呼叫
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" />
這項活動隨即會顯示如下的彈出式選單:
Kotlin
fun showPopup(v: View) { val popup = PopupMenu(this, v) val inflater: MenuInflater = popup.menuInflater inflater.inflate(R.menu.actions, popup.menu) popup.show() }
Java
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()
加載選單。
當使用者選取一個項目或輕觸選單區域之外的區域時,選單就會關閉。您可以使用 PopupMenu.OnDismissListener
監聽關閉事件。
處理點擊事件
若要在使用者選取一個選單項目時執行一項動作,您必須實作 PopupMenu.OnMenuItemClickListener
介面,並呼叫 setOnMenuItemclickListener()
將其註冊到 PopupMenu
。使用者選取項目時,系統會在介面中呼叫 onMenuItemClick()
回呼。
例如:
Kotlin
fun showMenu(v: View) { PopupMenu(this, v).apply { // MainActivity implements OnMenuItemClickListener setOnMenuItemClickListener(this@MainActivity) inflate(R.menu.actions) show() } } override fun onMenuItemClick(item: MenuItem): Boolean { return when (item.itemId) { R.id.archive -> { archive(item) true } R.id.delete -> { delete(item) true } else -> false } }
Java
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; } }
建立選單群組
選單群組是指一組共用特定特色的選單項目集合。透過這個群組,您可以:
- 用
setGroupVisible()
顯示或隱藏所有項目 - 用
setGroupEnabled()
啟用或停用所有項目 - 指定是否可使用
setGroupCheckable()
核選所有項目
您可以在選單資源中的 <group>
元素內建立巢狀結構 <item>
元素,以此建立一個群組,或透過 add()
方法指定群組 ID。
以下是含有群組的選單資源範例:
<?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>
群組中的項目會與第一個項目顯示同一級別,選單中所有三個項目均為同層級。不過,您可以參照群組 ID 並使用上述方法修改群組中兩個項目的特性。系統也不會將同一群組的項目分開。舉例來說,如果您為每個項目宣告 android:showAsAction="ifRoom"
,這兩者會同時顯示在動作列上,或同時顯示在溢位操作中。
使用可勾選的選單項目

圖 5. 具有可核選項目的子選單截圖。
選單對於開啟和關閉選項來說是很實用的介面,核取方塊則用於獨立選項,而互斥選項的群組則可使用圓形按鈕。圖 5 顯示的是可透過圓形按鈕勾選項目的子選單。
注意:圖示選單中的選單項目(來自選項選單)無法顯示核取方塊或圓形按鈕。如果您想要讓圖示選單中的項目可以核取,則必須每次在變更狀態時切換圖示及/或文字,以手動的方式顯示選取狀態。
您可以使用 <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
- 所有項目均可勾選(核取方塊)
none
- 沒有項目可供勾選
您可以透過 <item>
元素中的 android:checked
屬性,將某個項目預設為勾選狀態,接著用 setChecked()
方法在程式碼中變更。
如果選取了一個可勾選項目,系統會呼叫所選項目的回呼方法(例如 onOptionsItemSelected()
)。您必須在此設定核取方塊的狀態,因為核取方塊或圓形按鈕不會自動變更狀態。您可以使用 isChecked()
查詢項目目前的狀態(也就是使用者選取該項目前的狀態),接著使用 setChecked()
將其狀態設定為已勾選。例如:
Kotlin
override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.vibrate, R.id.dont_vibrate -> { item.isChecked = !item.isChecked true } else -> super.onOptionsItemSelected(item) } }
Java
@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); } }
如果您未以這種方式設定勾選狀態,則使用者選取該項目(核取方塊或圓形按鈕)時,視覺上的狀態不會改變。若您設定了狀態,活動會保留項目勾選的狀態,因此當使用者之後開啟選單時,就可以看到您設定的已勾選狀態。
注意:可勾選的選單項目僅適用於該工作階段使用,且在刪除應用程式後不會儲存。如果您的應用程式設定會為使用者儲存,則應使用共用偏好設定儲存資料。
根據意圖新增選單項目
有時候,您可能想讓選單項目使用 Intent
啟動活動(無論是您的應用程式或其他應用程式中的活動)。如果您知道要使用的意圖為何,而且具有可啟動該意圖的特定選單項目,就可以在適當的選取項目回呼方法(例如 onOptionsItemSelected()
回呼)中,使用 startActivity()
執行意圖。
然而,如果您不確定使用者裝置是否具有會處理該意圖的應用程式,那麼新增會叫用該意圖的選單項目,可能會導致選單項目無法運作,因為該意圖可能無法解析活動。為了解決這個問題,當 Android 在處理您的意圖的裝置上找到活動時,您可透過動態的方式將選單項目加入選單。
若要根據現有可接受意圖的活動新增選單項目:
- 將意圖定義為類別
CATEGORY_ALTERNATIVE
及/或CATEGORY_SELECTED_ALTERNATIVE
,以及任何其他要求。 - 呼叫
Menu.addIntentOptions()
。Android 會搜尋可執行這項意圖的應用程式,並將應用程式加入選單。
如果沒有安裝任何符合這項意圖的應用程式,系統就不會新增選單項目。
注意:
CATEGORY_SELECTED_ALTERNATIVE
用於處理目前在螢幕中選取的元素。因此,只有在 onCreateContextMenu()
中建立選單時才能使用。
例如:
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { 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. val intent = Intent(null, dataUri).apply { 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.componentName, // 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 }
Java
@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; }
系統會找到提供意圖篩選器並符合所定義意圖的每個活動,並為其新增選單項目,以意圖篩選器的 android:label
值做為選單項目標題,並以應用程式圖示作為選單的項目圖示。addIntentOptions()
方法會傳回新增選單項目的數量。
注意:在呼叫 addIntentOptions()
時,它會以第一個引數中指定的選單群組,覆寫選單中的任何及所有項目。
將活動新增至其他選單
也可以將您的活動服務提供給其他應用程式,您的應用程式就可以被納入其他應用程式的選單中(將上述角色反轉過來)。
若要加至其他應用程式的選單中,必須一如往常定義意圖篩選器,但請務必加入意圖篩選器類別的 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>
若要進一步瞭解如何編寫意圖篩選器,請參閱意圖及意圖篩選器一文。