新增菜單

試用 Compose
Jetpack Compose 是 Android 推薦的 UI 工具包。瞭解如何在 Compose 中新增元件。

選單是多種應用程式常見的使用者介面元件。如要提供一致且一致的使用者體驗,請使用 Menu API 在活動中顯示使用者動作和其他選項。

顯示溢位選單範例的圖片
圖 1.由輕觸圖示觸發的選單,顯示在溢位選單圖示下方。

本文將說明如何在所有版本的 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"
          app: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> 的子項。如果應用程式有許多功能可以依主題分類,例如電腦應用程式選單列中的各個項目 (例如「File」、「Edit」和「View」),子選單就非常實用。請參閱以下範例:

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

如要在活動中使用選單,請「inflate」選單資源,並使用 MenuInflater.inflate() 將 XML 資源轉換為可編寫程式的物件。以下各節將說明如何為每種選單類型加載選單。

建立選項選單

選項選單 (例如圖 1 所示的選項選單) 可讓您加入與目前活動情境相關的動作和其他選項,例如「搜尋」、「撰寫電子郵件」及「設定」。

這張圖片顯示 Google 試算表應用程式的應用程式列
圖 2. Google 試算表應用程式,顯示多個按鈕,包括動作溢位按鈕在內。

您可以在 Activity 子類別或 Fragment 子類別中宣告選項選單的項目。如果您的活動和片段都宣告了選項選單的項目,系統會在 UI 中合併項目。活動的項目會先顯示,然後依照片段新增至活動的順序,依序顯示各個片段的項目。如有需要,您可以在每個需要移動的 <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 修改這些項目的屬性。

處理點擊事件

當使用者從選項選單中選取項目 (包括應用程式列中的動作項目) 時,系統會呼叫活動的 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() 的父類別實作。預設實作方式會傳回 false。

如果活動含有片段,系統會先針對活動呼叫 onOptionsItemSelected(),然後針對各個片段按照新增順序排列,直到一個片段傳回 true 或所有片段都被呼叫為止。

在執行階段變更選單項目

系統呼叫 onCreateOptionsMenu() 後,會保留填入的 Menu 例項,且除非選單失效,否則不會再次呼叫 onCreateOptionsMenu()。不過,請只使用 onCreateOptionsMenu() 建立初始選單狀態,不要在活動生命週期期間進行變更。

若要根據活動生命週期中發生的事件修改選項選單,可以使用 onPrepareOptionsMenu() 方法。此方法會向您傳遞目前存在的 Menu 物件,因此您可以新增、移除或停用項目等。片段也會提供 onPrepareOptionsMenu() 回呼。

應用程式列顯示選單項目時,選項選單會視為一律開啟。當事件發生且您想更新選單時,請呼叫 invalidateOptionsMenu() 以要求系統呼叫 onPrepareOptionsMenu()

建立內容選單

顯示浮動內容選單的圖片
圖 3. 浮動內容選單。

內容選單提供的操作會影響 UI 中的特定項目或內容畫面。您可以為任何檢視畫面提供內容選單,但它們通常用於 RecylerView 或其他檢視區塊集合中的項目,讓使用者可以直接對各個項目執行操作。

提供內容關聯操作的方法有兩種:

  • 浮動內容選單中。當使用者對特定檢視畫面執行按住,且該檢視畫面宣告支援內容選單時,選單就會以浮動式清單的形式顯示選單項目清單,類似於對話方塊。使用者一次可以對一個項目執行內容關聯操作。
  • 關聯動作模式中。這個模式是 ActionMode 的系統實作,會在螢幕頂端顯示關聯動作列(簡稱 CAB),其中包含會影響所選項目的操作項目。啟用此模式後,如果應用程式支援這項功能,使用者就能一次對多個項目執行一項操作。

注意: 內容選單不支援項目捷徑和項目圖示。

建立浮動內容選單

如要提供浮動內容選單,請執行下列步驟:

  1. 呼叫 registerForContextMenu() 並傳遞 View,註冊與內容選單相關聯的 View

    如果活動使用 RecyclerView,而您希望每個項目都提供相同的內容選單,請將 RecyclerView 傳遞至 registerForContextMenu(),註冊內容選單的所有項目。

  2. 在您的 ActivityFragment 中實作 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 物件。如果活動有多個檢視畫面,且每個檢視畫面提供不同的內容選單,您可以利用這些參數來判斷要加載哪些內容選單。

  3. 實作 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 傳回。如果您不處理選單項目,請將選單項目傳遞至父類別實作。如果活動含有片段,活動會先收到這個回呼。在未處理的情況下呼叫父類別時,系統會按照每個片段的新增順序,將事件逐一傳遞到每個片段中相應的回呼方法,直到傳回 truefalse 為止。Activityandroid.app.Fragment 的預設實作會傳回 false,因此在未處理時一律呼叫父類別。

使用關聯動作模式

關聯動作模式是 ActionMode 的系統實作項目,著重於使用者互動,以執行關聯動作。當使用者選取某個項目啟用此模式時,螢幕頂端會出現關聯動作列,以顯示使用者可以對選取項目執行的操作。啟用此模式後,使用者就可以選取多個項目,如果應用程式支援這項功能,則可取消選取項目,並繼續在活動中瀏覽。當使用者取消選取所有項目、輕觸「Back」按鈕或輕觸列左側的「Done」動作時,操作模式即會停用,關聯動作列會消失。

針對提供內容關聯操作的檢視畫面,如果發生下列一或兩個事件,您通常會叫用關聯動作模式:

  • 使用者按住檢視畫面。
  • 使用者在檢視畫面中選取核取方塊或類似的 UI 元件。

您的應用程式如何叫用關聯動作模式,並根據您的設計定義每個操作的行為。目前有兩種設計:

  • 用於個別任意檢視畫面的內容關聯操作。
  • 針對 RecyclerView 中的項目群組批次關聯操作,可讓使用者選取多個項目並執行所有動作。

以下章節介紹了各個情境所需的設定。

為個別檢視畫面啟用關聯動作模式

如果只想在使用者選取特定檢視畫面時叫用關聯動作模式,請執行下列步驟:

  1. 實作 ActionMode.Callback 介面,如以下範例所示。在回呼方法中,您可以指定關聯動作列的操作、回應操作項目的點擊事件,以及為操作模式處理其他生命週期事件。

    Kotlin

        private val actionModeCallback = object : ActionMode.Callback {
            // Called when the action mode is created. startActionMode() is 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, and might 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() is 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, and might 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。在下一步中,請參閱初始化方式,以及在活動或片段中儲存成員變數的實用程度。

  2. 如要顯示長條 (例如使用者按住檢視畫面時),請呼叫 startActionMode()

    Kotlin

        someView.setOnLongClickListener { view ->
            // Called when the user performs a touch & hold on someView.
            when (actionMode) {
                null -> {
                    // Start the CAB using the ActionMode.Callback defined earlier.
                    actionMode = activity?.startActionMode(actionModeCallback)
                    view.isSelected = true
                    true
                }
                else -> false
            }
        }
        

    Java

        someView.setOnLongClickListener(new View.OnLongClickListener() {
            // Called when the user performs a touch & hold on someView.
            public boolean onLongClick(View view) {
                if (actionMode != null) {
                    return false;
                }
    
                // Start the CAB using the ActionMode.Callback defined earlier.
                actionMode = getActivity().startActionMode(actionModeCallback);
                view.setSelected(true);
                return true;
            }
        });
        

    當您呼叫 startActionMode() 時,系統會傳回建立的 ActionMode。將此項目儲存至成員變數中,即可變更關聯動作列以回應其他事件。在上述範例中,ActionMode 是用來確保在活動期間不會重新建立 ActionMode 執行個體,方法是先檢查成員的值是否為空值,接著再啟動動作模式。

建立彈出式選單

這張圖片顯示 Gmail 應用程式的彈出式選單,選單固定在右上方的溢位按鈕上。
圖 4. Gmail 應用程式中的彈出式選單,固定於右上角的溢位按鈕。

PopupMenu 是固定在 View 的強制回應選單。如果有空間,它會顯示在錨定檢視畫面下方,否則會顯示在檢視畫面上方。這在以下情況相當實用:

  • 為與特定內容 (例如圖 4 所示的 Gmail 電子郵件標頭) 相關的操作提供溢位樣式選單。
  • 提供指令句的第二部分,例如標示「Add」的按鈕,可產生包含不同「Add」選項的彈出式選單。
  • 提供類似 Spinner 的選單,但不會保留永久選項。

如果您以 XML 定義選單,以下是顯示彈出式選單的方式:

  1. 利用其建構函式將 PopupMenu 執行個體化,此操作會將目前應用程式的 ContextView 帶到選單錨定的地方。
  2. 使用 MenuInflater 將選單資源加載至 PopupMenu.getMenu() 傳回的 Menu 物件。
  3. 呼叫 PopupMenu.show()

例如,以下是顯示彈出式選單的按鈕:

<ImageButton
    android:id="@+id/dropdown_menu"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:contentDescription="@string/descr_overflow_button"
    android:src="@drawable/arrow_drop_down" />

這項活動隨即會顯示如下的彈出式選單:

Kotlin

findViewById<ImageButton>(R.id.dropdown_menu).setOnClickListener {
    val popup = PopupMenu(this, it)
    val inflater: MenuInflater = popup.menuInflater
    inflater.inflate(R.menu.actions, popup.menu)
    popup.show()
}

Java

findViewById(R.id.dropdown_menu).setOnClickListener(v -> {
    PopupMenu popup = new PopupMenu(this, v);
    popup.getMenuInflater().inflate(R.menu.actions, popup.getMenu());
    popup.show();
});

當使用者選取某個項目,或輕觸選單區域外的輕觸時,選單就會關閉。您可以使用 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;
    }
}

建立選單群組

選單群組是指一組共用特定特色的選單項目集合。您可以透過群組執行下列操作:

您可以在選單資源中的 <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 在處理您的意圖的裝置上找到活動時,您可透過動態的方式將選單項目加入選單。

如要根據可接受意圖的活動新增選單項目,請執行下列步驟:

  1. 定義意圖具有 CATEGORY_ALTERNATIVECATEGORY_SELECTED_ALTERNATIVE 類別,或兩者並用,以及任何其他規定。
  2. 呼叫 Menu.addIntentOptions()。Android 會搜尋可執行意圖的應用程式,並將其新增至選單。

如果沒有安裝任何符合意圖的應用程式,系統就不會新增選單項目。

例如:

Kotlin

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)

    // Create an Intent that describes the requirements to fulfill, to be
    // included in the 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 apps.
    menu.addIntentOptions(
            R.id.intent_group,  // Menu group to which new items are 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 the 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 the 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 apps.
    menu.addIntentOptions(
         R.id.intent_group,         // Menu group to which new items are 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 the requirements.
         0,                         // Additional flags to control items (none).
         null);                     // Array of MenuItems that correlate to specific items (none).

    return true;
}

系統會找到提供意圖篩選器並符合所定義意圖的每個活動,並為其新增選單項目,以意圖篩選器的 android:label 值做為選單項目標題,並以應用程式圖示做為選單項目圖示。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>

如要進一步瞭解如何編寫意圖篩選器,請參閱意圖和意圖篩選器