创建菜单组

创建菜单组

尝试使用 Compose 方式

Jetpack Compose 是推荐用于 Android 的界面工具包。了解如何在 Compose 中添加组件。

菜单 →

菜单是许多应用类型中常见的界面组件。为了提供熟悉且一致的用户体验,请使用 Menu API 呈现 activity 中的用户操作和其他选项。

注意:为了获得更好的用户体验,请参阅 Material Design 菜单。

图 1. 通过点按图标触发的菜单,显示在溢出菜单图标下方。

本文档将介绍所有 Android 版本中三种基本菜单或操作呈现效果的创建方法:

选项菜单和应用栏

选项菜单是 activity 的主菜单项集合,供您放置对应用产生全局影响的操作,如“搜索”“撰写电子邮件”和“设置”。

请参阅创建选项菜单部分。

上下文菜单和关联操作模式

上下文菜单是用户轻触并按住某元素时出现的悬浮菜单。该菜单提供的操作会影响所选内容或上下文框架。

关联操作模式在屏幕顶部栏显示影响所选内容的操作项,并允许用户选择多项内容。

请参阅创建上下文菜单部分。

弹出式菜单

弹出式菜单以垂直列表形式显示一系列菜单项,并且该列表会锚定到调用该菜单的视图中。它特别适用于提供与特定内容相关的大量操作,或者为命令的后续部分提供选项。弹出式菜单中的操作不会直接影响相应的内容,而关联操作则会对其产生影响。相反,弹出式菜单适用于与 Activity 中的内容区域相关的扩展操作。

请参阅创建弹出式菜单部分。

在 XML 中定义菜单

对于所有菜单类型,Android 提供标准的 XML 格式来定义菜单项。您应在 XML 菜单资源中定义菜单及其所有菜单项,而非在 activity 的代码中构建菜单。然后,您可以在 activity 或 fragment 中膨胀菜单资源(将其作为 Menu 对象加载)。

使用菜单资源是一种很好的做法,原因如下:

利用 XML 更易于直观掌握菜单结构。

将菜单内容与应用的行为代码分离。

您可以利用应用资源框架,针对不同的平台版本、屏幕尺寸和其他配置创建备用菜单配置。

如需定义菜单,请在项目的 res/menu/ 目录内创建 XML 文件,并使用以下元素构建菜单:

定义 Menu,即菜单项的容器。

元素必须是该文件的根节点,并且可以包含一个或多个 元素。

创建 MenuItem,此元素表示菜单中的一个菜单项。此元素可以包含嵌套的

元素,以创建子菜单。

元素的不可见容器(可选)。利用该元素,您可以对菜单项进行分类,使同类元素共享活动状态和可见性等属性。如需了解详情,请参阅创建菜单组部分。

以下是名为 game_menu.xml 的菜单示例:

android:icon="@drawable/ic_new_game"

android:title="@string/new_game"

app:showAsAction="ifRoom"/>

android:icon="@drawable/ic_help"

android:title="@string/help" />

元素支持多个属性,您可使用这些属性定义菜单项的外观和行为。上述菜单中的菜单项包括以下属性:

android:id

菜单项独有的资源 ID,让应用能够在用户选择菜单项时识别该菜单项。

android:icon

引用一个要用作菜单项图标的可绘制对象。

android:title

引用一个要用作菜单项标题的字符串。

android:showAsAction

此菜单项在应用栏中作为操作项显示的时间和方式的规范。

这些是您使用的最重要的属性,但还有许多其他可用属性。如需了解所有受支持的属性,请参阅菜单资源文档。

您可以添加

元素作为 的子元素,从而向任何菜单中的菜单项添加子菜单。当应用具有大量可按主题进行组织的功能时,子菜单非常有用,PC 应用菜单栏中的菜单项(例如文件、编辑和视图)就属于这种情况。具体请参阅下例:

android:title="@string/file" >

android:title="@string/create_new" />

android:title="@string/open" />

如需在 activity 中使用菜单,请使用 MenuInflater.inflate() 膨胀菜单资源,将 XML 资源转换为可编程对象。以下部分展示了如何膨胀每种菜单类型的菜单。

创建选项菜单

选项菜单(如图 1 所示)用于包含与当前 activity 上下文相关的操作和其他选项,如“搜索”“撰写电子邮件”和“设置”。

图 2. Google 表格应用,显示了包括操作溢出按钮在内的多个按钮。

您可以通过 Activity 子类或 Fragment 子类为选项菜单声明菜单项。如果您的 activity 和 fragment 均为选项菜单声明了菜单项,这些菜单项会合并到界面中。系统会先显示 activity 的菜单项,然后按 fragment 添加至 activity 的顺序显示各 fragment 的菜单项。如有必要,您可以使用 android:orderInCategory 属性,对每个需移动的 中的菜单项重新排序。

如需为 activity 指定选项菜单,请替换 onCreateOptionsMenu()。Fragment 提供自己的 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 修改其属性。

处理点击事件

当用户从选项菜单中选择菜单项(包括应用栏中的操作项)时,系统会调用 Activity 的 onOptionsItemSelected() 方法。此方法会传递所选的 MenuItem。您可以通过调用 getItemId() 方法来识别菜单项,该方法会返回菜单项的唯一 ID,该 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。

如果您的 activity 包含 fragment,系统会先为 activity 调用 onOptionsItemSelected(),然后按照 fragment 的添加顺序为每个 fragment 调用 onOptionsItemSelected(),直到有一个 fragment 返回 true 或所有 fragment 都被调用为止。

提示:如果应用包含多个 activity,且其中某些 activity 提供相同的选项菜单,可以考虑创建一个仅实现 onCreateOptionsMenu() 和 onOptionsItemSelected() 方法的 activity。然后,为每个共用相同选项菜单的 activity 扩展此类。通过这种方式,您可以管理一个用于处理菜单操作的代码集,并且每个后代类均会继承菜单行为。若要将菜单项添加到其中某个后代 activity,请替换该 activity 中的 >onCreateOptionsMenu()。调用 super.onCreateOptionsMenu(menu),以便创建原始菜单项,然后使用 menu.add() 添加新菜单项。此外,您还可替换各个菜单项的超类行为。

在运行时更改菜单项

系统调用 onCreateOptionsMenu() 后,会保留您填充的 Menu 实例。除非菜单失效,否则系统不会再次调用 onCreateOptionsMenu()。不过,您只应使用 onCreateOptionsMenu() 来创建初始菜单状态,而不应使用它在 activity 生命周期中执行任何更改。

如需根据在 activity 生命周期中发生的事件修改选项菜单,可通过 onPrepareOptionsMenu() 方法执行此操作。此方法向您传递 Menu 对象(因为该对象目前存在),以便您能够对其进行修改,如添加、移除或停用菜单项。Fragment 还提供 onPrepareOptionsMenu() 回调。

当菜单项显示在应用栏中时,系统会将选项菜单视为始终处于打开状态。发生事件时,如果您要执行菜单更新,请调用 invalidateOptionsMenu() 来请求系统调用 onPrepareOptionsMenu()。

注意:切勿根据目前处于焦点的 View 更改选项菜单中的菜单项。

处于触摸模式(用户未使用轨迹球或方向键)时,视图无法形成焦点,因此切勿根据焦点修改选项菜单中的菜单项。若要为 View 提供上下文相关的菜单项,请使用上下文菜单,如下一部分中所述。

创建上下文菜单

图 3. 悬浮上下文菜单。

上下文菜单提供许多操作,这些操作会影响界面中的特定菜单项或上下文框架。您可以为任何视图提供上下文菜单,但这些菜单通常用于 RecylerView 或用户可直接操作其中每个菜单项的其他视图集合中的菜单项。

提供关联操作的方法有两种:

使用悬浮上下文菜单。当用户轻触并按住某个声明支持上下文菜单的视图时,菜单会显示为菜单项的悬浮列表(类似对话框)。用户一次可对一个菜单项执行关联操作。

使用关联操作模式。此模式是 ActionMode 的系统实现,它会在屏幕顶部显示“关联操作栏”(CAB),其中包含影响所选菜单项的操作项。当此模式处于活动状态时,用户可以同时对多个菜单项执行操作(如果应用支持)。

注意: 上下文菜单不支持项目快捷方式和项目图标。

创建悬浮上下文菜单

如需提供悬浮上下文菜单,请执行以下操作:

通过调用 registerForContextMenu() 并将 View 传递给它,注册与上下文菜单关联的 View。

如果您的 activity 使用 RecyclerView,并且您希望每个菜单项均提供相同的上下文菜单,请通过将 RecyclerView 传递给 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 对象。如果您的 activity 有多个视图,每个视图提供的上下文菜单不同,您可以使用这些参数确定要膨胀的上下文菜单。

实现 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,您应在 XML 中使用 android:id 属性将此 ID 分配给每个菜单项(如使用 XML 定义菜单部分所示)。

成功处理菜单项后,系统会返回 true。如果您未处理菜单项,请将菜单项传递给父类实现。如果 activity 包含 fragment,则该 activity 会先收到此回调。通过在未处理的情况下调用父类,系统会(按照每个 fragment 的添加顺序)将事件逐一传递给每个 fragment 中相应的回调方法,直到返回 true 或 false 为止。Activity 和 android.app.Fragment 的默认实现会返回 false,因此您始终应在未处理的情况下调用父类。

使用关联操作模式

关联操作模式是 ActionMode 的一种系统实现,它将用户互动的重点放在执行关联操作上。当用户通过选择菜单项启用此模式时,屏幕顶部会出现“关联操作栏”,显示用户可对所选菜单项执行的操作。启用此模式后,用户可以选择多个菜单项(如果您的应用支持),还可以取消选择菜单项并继续在 activity 内导航。当用户取消选择所有菜单项、点按“返回”按钮或点按操作栏左侧的“完成”操作时,该操作模式将会停用,而关联操作栏也会消失。

注意:关联操作栏不一定与应用栏相关联。尽管表面上看来关联操作栏取代了应用栏的位置,但事实上二者独立运行。

对于提供关联操作的视图,当出现以下两个事件(或之一)时,您通常应调用关联操作模式:

用户轻触并按住视图。

用户选中复选框或视图内类似的界面组件。

应用如何调用关联操作模式以及如何定义每个操作的行为取决于您的设计。共有两种设计:

针对单个任意视图的关联操作。

针对 RecyclerView 中菜单项组的批处理关联操作,允许用户选择多个菜单项并针对所有菜单项执行操作。

下面几部分介绍了第一种场景所需的设置。

为单个视图启用关联操作模式

如果只想在用户选择特定视图时调用关联操作模式,请执行以下操作:

实现 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。在下一步中,您将了解如何初始化该变量,以及保存 Activity 或 Fragment 中的成员变量有何作用。

当需要显示操作栏时(例如,当用户轻触并按住视图时),请调用 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 用于在启动该操作模式前检查成员是否为 null,从而确保当 ActionMode 实例已激活时不再重建该实例。

创建弹出式菜单

图 4. Gmail 应用中的弹出式菜单,锚定到右上角的溢出按钮。

PopupMenu 是锚定在 View 中的模态菜单。如果空间足够,它会显示在锚定视图下方,否则显示在其上方。它适用于以下情况:

为与特定内容相关的操作提供溢出样式菜单(例如,Gmail 的电子邮件标头,如图 4 所示)。

注意:这与上下文菜单不同,后者通常用于影响所选内容的操作。

对于影响所选内容的操作,请使用关联操作模式或悬浮上下文菜单。

提供命令语句的另一部分,例如标记为添加且使用不同的添加选项生成弹出式菜单的按钮。

提供类似于 Spinner 且不保留永久选择的菜单。

如果使用 XML 定义菜单,弹出式菜单的显示方式如下:

实例化 PopupMenu 及其构造函数,该函数接受当前应用的 Context 以及菜单锚定的 View。

使用 MenuInflater 将菜单资源膨胀到 PopupMenu.getMenu() 返回的 Menu 对象中。

调用 PopupMenu.show()。

例如,以下是一个显示弹出式菜单的按钮:

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" />

稍后,Activity 可按如下方式显示弹出式菜单:

Kotlin

findViewById(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;

}

}

创建菜单组

菜单组是指一系列具有某些共同特征的菜单项。借助群组,您可以执行以下操作:

使用 setGroupVisible() 显示或隐藏所有菜单项。

使用 setGroupEnabled() 启用或停用所有菜单项。

使用 setGroupCheckable() 指定所有菜单项是否可选中。

通过将 元素嵌套在菜单资源中的 元素内,或者通过使用 add() 方法指定组 ID,您可以创建组。

以下是包含组的菜单资源示例:

android:icon="@drawable/menu_save"

android:title="@string/menu_save" />

android:title="@string/menu_archive" />

android:title="@string/menu_delete" />

组中的菜单项出现在与第一个菜单项相同的级别,即:菜单中的全部三个菜单项均为同级。不过,您可以通过引用组 ID 并使用上述方法,修改组中两个菜单项的特征。此外,系统也绝不会将已分组的菜单项分开。例如,如果为每个菜单项声明 android:showAsAction="ifRoom",它们就会同时显示在操作栏或操作溢出菜单中。

使用可选中的菜单项

图 5. 包含可选中菜单项的子菜单。

菜单非常适合用作启用/停用选项的界面,既可针对独立选项使用复选框,也可针对互斥选项组使用单选按钮。图 5 展示了可使用单选按钮选中菜单项的子菜单。

注意:选项菜单中的菜单项无法显示复选框或单选按钮。如果您使选项菜单中的菜单项可选中,就必须在选中状态每次发生变化时交换图标和/或文本,从而手动指出该状态。

您可以在 元素中使用 android:checkable 属性为各个菜单项定义可选中的行为,或者在 元素中使用 android:checkableBehavior 属性为整个组定义可选中的行为。例如,此菜单组中的所有菜单项都可以通过单选按钮选中:

android:title="@string/red" />

android:title="@string/blue" />

android:checkableBehavior 属性接受以下值之一:

single

组中只能勾选一个菜单项,因此会显示单选按钮。

all

所有项均可勾选,从而显示复选框。

none

所有菜单项均无法选中。

您可以在 元素中使用 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);

}

}

如果未通过这种方式设置选中状态,那么复选框或单选按钮的可见状态不会在用户选择它时发生变化。如果设置了该状态,Activity 会保留菜单项的选中状态。如此一来,当用户稍后打开菜单时,您设置的选中状态便会处于可见状态。

注意:可选中菜单项的使用往往因会话而异,且在应用销毁后不予保存。如果您想为用户保存某些应用设置,请使用共享存储空间存储数据。

添加基于 intent 的菜单项

有时,您会希望菜单项使用 Intent 启动 activity(无论该 activity 是在您的应用中还是其他应用中)。如果您知道自己要使用的 intent,且拥有启动该 intent 的特定菜单项,您可以在相应的 on-item-selected 回调方法(例如 onOptionsItemSelected() 回调)期间使用 startActivity() 执行该 intent。

不过,如果不确定用户的设备是否包含可处理该 intent 的应用,添加调用该 intent 的菜单项可能会导致该菜单项无法正常工作,因为该 intent 可能无法解析为 activity。为解决此问题,当 Android 在设备上找到可处理您的 intent 的 activity 时,其会允许您向菜单动态添加菜单项。

如要根据接受 Intent 的可用 activity 添加菜单项,请执行以下操作:

使用类别 CATEGORY_ALTERNATIVE 或 CATEGORY_SELECTED_ALTERNATIVE(或两者兼有)以及任何其他要求定义 intent。

调用 Menu.addIntentOptions()。

Android 随后会搜索能够执行该 intent 的所有应用,并将其添加到菜单中。

如果未安装可处理该 intent 的应用,系统不会添加任何菜单项。

注意: 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 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;

}

但凡发现 Activity 提供的 intent 过滤器与定义的 intent 匹配,系统就会为相应 Activity 添加菜单项,并使用 intent 过滤器 android:label 中的值作为菜单项标题,使用应用图标作为菜单项图标。addIntentOptions() 方法会返回已添加的菜单项数量。

注意:调用 addIntentOptions() 时,该方法会使用第一个实参中指定的菜单组替换所有菜单项。

允许将您的 activity 添加到其他菜单中

您可以为其他应用提供您的 activity 服务,以便其他应用的菜单中能加入您的应用(与上述作用相反)。

如要在其他应用菜单中加入您的应用,请按常规方式定义 intent 过滤器,但请为 intent 过滤器类别添加 CATEGORY_ALTERNATIVE 和/或 CATEGORY_SELECTED_ALTERNATIVE 值。具体可见以下示例:

...

...

如需详细了解如何编写 intent 过滤器,请参阅 intent 和 intent 过滤器。

相关文章

bat365在线登录
汉字“忐”的起源与演变(源流)
bat365官网登录下载
蚂蚱:自然乐章中的跳跃精灵