選單是一種適用於多種應用程式的常見使用者介面元件。為了提供熟悉且一致的使用者體驗,您應在活動中使用 Menu
API 為使用者呈現動作和其他選項。
從 Android 3.0 (API 級別 11) 開始,搭載 Android 的裝置不再需要提供專用的「Munu」(選單) 按鈕。在這項改變下,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
的系統實作,著重於將使用者互動轉為執行關聯操作。當使用者選取某個項目啟用此模式時,螢幕頂端會出現關聯動作列,以顯示使用者可以對目前選取項目執行的操作。啟用此模式後,使用者就可以選取多個項目 (如果您允許的話)、取消選取項目,以及繼續在活動中瀏覽 (視您允許的情況而定)。當使用者取消選取所有項目、按下「BACK」(返回) 按鈕或選取列左側的「Done」(完成) 動作時,操作模式即會停用,關聯動作列會消失。
注意:關聯動作列不需與應用程式列有所關聯。雖然關聯動作列看起來會出現在應用程式列的位置,但它們是獨立作業的。
針對提供內容關聯操作的檢視畫面,通常應在兩個事件之一 (或兩者) 上叫用關聯動作模式:
- 使用者長按檢視畫面。
- 使用者在檢視畫面中選取核取方塊或類似的 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>
若要進一步瞭解如何編寫意圖篩選器,請參閱意圖及意圖篩選器一文。