新增菜單

試試 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> 的子項,即可在任何選單中為項目新增子選單。如果應用程式有許多功能可以依主題分類,就如同電腦應用程式選單列中的各個項目 (「檔案」、「編輯」和「檢視」等),就可以用到子選單。請參閱以下範例:

<?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 所示) 可用來加入與目前活動情境相關的操作和其他選項,例如「搜尋」、「撰寫電子郵件」和「設定」。

圖片:顯示 Google 試算表應用程式選單列
圖 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 關聯的屬性。

處理點擊事件

當使用者從選項選單中選取項目 (包括應用程式列中的動作項目) 時,系統會呼叫活動的 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. 浮動內容選單。

內容選單可提供會影響使用者介面中特定項目或內容畫面的操作。您可以為任何檢視畫面提供內容選單,但它們通常用於 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 的系統實作,著重於將使用者互動轉為執行關聯操作。當使用者選取某個項目啟用此模式時,螢幕頂端會出現關聯動作列,以顯示使用者可以對所選項目執行的操作。啟用此模式後,使用者可以選取多個項目 (如果應用程式支援的話),並取消選取項目,以及繼續在活動中瀏覽。當使用者取消選取所有項目、輕觸「返回」按鈕,或是輕觸列左側的「完成」動作時,操作模式即會停用,關聯動作列會消失。

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

  • 使用者按住檢視畫面。
  • 使用者在檢視畫面中選取核取方塊或類似的 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_ALTERNATIVECATEGORY_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>

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