菜单
菜单是许多类型的应用程序中的常见用户界面组件。要提供熟悉且一致的用户体验,您应使用菜单API在活动中显示用户操作和其他选项。
从Android 3.0(API级别11)开始,不再需要Android驱动的设备来提供专用的菜单按钮。通过此更改,Android应用程序应远离对传统的6项菜单面板的依赖,而是提供应用栏以显示常见的用户操作。
尽管某些菜单项的设计和用户体验已发生变化,但定义一组操作和选项的语义仍基于Menu API。本指南介绍如何在所有Android版本上创建三种基本类型的菜单或操作演示:
选项菜单和应用栏
选项菜单是活动的主菜单项集合。您应该在此处放置对应用程序具有全局影响的操作,例如“搜索”,“撰写电子邮件”和“设置”。
请参阅有关创建选项菜单的部分。
上下文菜单和上下文操作模式
上下文菜单是当用户对元素执行长按时显示的浮动菜单。它提供影响所选内容或上下文框架的操作。
上下文操作模式显示影响屏幕顶部栏中所选内容的操作项,并允许用户选择多个项。
请参阅有关创建上下文菜单的部分。
弹出菜单
弹出菜单显示垂直列表中的项目列表,该列表锚定到调用菜单的视图。提供与特定内容相关的动作溢出或为命令的第二部分提供选项是有益的。弹出菜单中的操作不应直接影响相应的内容 - 这是上下文操作的用途。而是,弹出菜单用于与活动中的内容区域相关的扩展操作。
请参阅有关创建弹出菜单的部分。
在XML中定义菜单
对于所有菜单类型,Android提供标准XML格式来定义菜单项。您应该在XML菜单资源中定义菜单及其所有项目,而不是在活动代码中构建菜单。然后,您可以在活动或片段中夸大菜单资源(将其作为Menu对象加载)。
使用菜单资源是一种很好的做法,原因如下:
- 在XML中可视化菜单结构更容易。
- 它将菜单内容与应用程序的行为代码分开。
- 它允许您通过利用应用程序资源框架为不同的平台版本,屏幕大小和其他配置创建备用菜单配置。
要定义菜单,请在项目的res / menu /目录中创建XML文件,并使用以下元素构建菜单:
<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
对drawable的引用,用作项目的图标。
android:title
对用作项目标题的字符串的引用。
android:showAsAction
指定此项目应在应用栏中显示为操作项的时间和方式。
这些是您应该使用的最重要的属性,但还有更多可用的属性。有关所有受支持属性的信息,请参阅“菜单资源”文档。
您可以通过添加<menu>元素作为<item>的子项,在任何菜单(子菜单除外)中为项目添加子菜单。当您的应用程序具有许多可以组织到主题中的功能(如PC应用程序的菜单栏中的项目(文件,编辑,视图等))时,子菜单非常有用。例如:
<?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资源转换为可编程对象)。在以下部分中,您将看到如何为每种菜单类型为菜单充气。
创建选项菜单

选项菜单中应包含与当前活动上下文相关的操作和其他选项,例如“搜索”,“撰写电子邮件”和“设置”。
选项菜单中的项目出现在屏幕上的位置取决于您为其开发应用程序的版本:
- 如果您已经开发了Android 2.3.x(API级别10)或更低版本的应用程序,当用户按下Menu按钮时,选项菜单的内容将显示在屏幕底部,如图1所示。打开时,第一个可见部分是图标菜单,最多可容纳六个菜单项。如果您的菜单包含六个以上的项目,Android会将第六个项目和其余项目放入溢出菜单,用户可以通过选择更多来打开该菜单。
- 如果您已经开发了适用于Android 3.0(API级别11)及更高版本的应用程序,则可以在应用栏中找到选项菜单中的项目。默认情况下,系统会将所有项目置于操作溢出中,用户可以使用应用栏右侧的操作溢出图标(或按设备菜单按钮,如果可用)显示该项目。要启用对重要操作的快速访问,可以通过将android:showAsAction =“ifRoom”添加到相应的<item>元素来促使应用栏中显示一些项目(参见图2)。
有关操作项和其他应用栏行为的更多信息,请参阅添加App Bar培训课程。

您可以从Activity子类或Fragment子类声明选项菜单的项。如果您的活动和片段都为选项菜单声明了项目,则它们将在UI中合并。首先显示活动的项目,然后按照每个片段添加到活动的顺序显示每个片段的项目。如有必要,您可以在需要移动的每个<item>中使用android:orderInCategory属性重新排序菜单项。
要指定活动的选项菜单,请覆盖onCreateOptionsMenu()(片段提供自己的onCreateOptionsMenu()回调)。在此方法中,您可以将菜单资源(在XML中定义)扩展到回调中提供的菜单中。例如:
@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与已知菜单项匹配,以执行相应的操作。例如:
@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或已调用所有片段。
提示:Android 3.0增加了使用android:onClick属性为XML中的菜单项定义点击行为的功能。属性的值必须是使用菜单的活动定义的方法的名称。该方法必须是公共的并接受单个MenuItem参数 - 当系统调用此方法时,它会传递所选的菜单项。有关更多信息和示例,请参阅菜单资源文档。
提示:如果您的应用程序包含多个活动,并且其中一些活动提供相同的选项菜单,请考虑创建除onCreateOptionsMenu()和onOptionsItemSelected()方法之外不执行任何操作的活动。然后为应该共享相同选项菜单的每个活动扩展此类。这样,您可以管理一组代码来处理菜单操作,每个后代类都继承菜单行为。如果要将菜单项添加到其中一个后代活动,请覆盖该活动中的onCreateOptionsMenu()。调用super.onCreateOptionsMenu(菜单)以创建原始菜单项,然后使用menu.add()添加新菜单项。您还可以覆盖单个菜单项的超类的行为。
在运行时更改菜单项
在系统调用onCreateOptionsMenu()之后,它会保留您填充的菜单的实例,并且不会再次调用onCreateOptionsMenu(),除非由于某种原因菜单失效。但是,您应该仅使用onCreateOptionsMenu()来创建初始菜单状态,而不是在活动生命周期中进行更改。
如果要根据活动生命周期中发生的事件修改选项菜单,可以在onPrepareOptionsMenu()方法中执行此操作。此方法会将Menu对象传递给当前存在,以便您可以对其进行修改,例如添加,删除或禁用项目。 (片段还提供onPrepareOptionsMenu()回调。)
在Android 2.3.x及更低版本中,每次用户打开选项菜单(按菜单按钮)时,系统都会调用onPrepareOptionsMenu()。
在Android 3.0及更高版本中,当应用栏中显示菜单项时,选项菜单被视为始终打开。当事件发生并且您想要执行菜单更新时,必须调用invalidateOptionsMenu()以请求系统调用onPrepareOptionsMenu()。
注意:您永远不应该根据当前焦点视图更改选项菜单中的项目。在触摸模式下(当用户没有使用轨迹球或d-pad时),视图无法获得焦点,因此您不应该使用焦点作为修改选项菜单中项目的基础。如果要提供对视图具有上下文相关性的菜单项,请使用上下文菜单。
创建上下文菜单

上下文菜单提供影响UI中特定项目或上下文框架的操作。您可以为任何视图提供上下文菜单,但它们通常用于ListView,GridView或其他视图集合中的项目,用户可以在其中对每个项目执行直接操作。
有两种方法可以提供上下文操作:
- 在浮动上下文菜单中。当用户在声明支持上下文菜单的视图上执行长按(按住)时,菜单显示为菜单项的浮动列表(类似于对话框)。用户可以一次对一个项目执行上下文操作。
- 在上下文动作模式中。此模式是ActionMode的系统实现,它在屏幕顶部显示一个上下文操作栏,其中包含影响所选项目的操作项。当此模式处于活动状态时,用户可以同时对多个项目执行操作(如果您的应用允许)。
注意:上下文操作模式在Android 3.0(API级别11)及更高版本上可用,并且是可用时显示上下文操作的首选技术。如果您的应用支持低于3.0的版本,那么您应该回到这些设备上的浮动上下文菜单。
创建浮动上下文菜单
要提供浮动上下文菜单:
1.通过调用registerForContextMenu()注册上下文菜单应关联的视图,并将其传递给View。
如果您的活动使用ListView或GridView并且您希望每个项目都提供相同的上下文菜单,请通过将ListView或GridView传递给registerForContextMenu()来注册上下文菜单的所有项目。
2.在Activity或Fragment中实现onCreateContextMenu()方法。
当注册的视图收到长按事件时,系统将调用onCreateContextMenu()方法。这是您定义菜单项的地方,通常是通过膨胀菜单资源。例如:
@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()。
当用户选择菜单项时,系统会调用此方法,以便您可以执行相应的操作。例如:
@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按钮或选择栏左侧的完成操作时,操作模式被禁用,上下文操作栏消失。
注意:上下文操作栏不一定与应用栏相关联。它们独立运行,即使上下文操作栏在视觉上超过应用栏位置。
对于提供上下文操作的视图,通常应该在两个事件(或两者)之一上调用上下文操作模式:
- 用户在视图上执行长按。
- 用户在视图中选择复选框或类似的UI组件。
应用程序如何调用上下文操作模式并定义每个操作的行为取决于您的设计。基本上有两种设计:
- 对于单个任意视图的上下文操作。
- 对于ListView或GridView中的项目组的批处理上下文操作(允许用户选择多个项目并对它们执行所有操作)。
以下部分描述了每个方案所需的设置。
为各个视图启用上下文操作模式
如果只想在用户选择特定视图时调用上下文操作模式,则应该:
1.实现ActionMode.Callback接口。在其回调方法中,您可以指定上下文操作栏的操作,响应操作项上的单击事件,以及处理操作模式的其他生命周期事件。
2.要显示栏时调用startActionMode()(例如,当用户长按视图时)。
例如:
1.实现ActionMode.Callback接口:
private ActionMode.Callback mActionModeCallback = 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) {
mActionMode = null;
}
};
请注意,这些事件回调几乎与选项菜单的回调完全相同,除了每个回调都传递与事件关联的ActionMode对象。您可以使用ActionMode API对CAB进行各种更改,例如使用setTitle()和setSubtitle()修改标题和副标题(用于指示选择了多少项)。
另请注意,上面的示例在销毁操作模式时将mActionMode变量设置为null。在下一步中,您将看到它是如何初始化的,以及如何在活动或片段中保存成员变量是有用的。
2.调用startActionMode()以在适当时启用上下文操作模式,例如响应对View的长按:
someView.setOnLongClickListener(new View.OnLongClickListener() {
// Called when the user long-clicks on someView
public boolean onLongClick(View view) {
if (mActionMode != null) {
return false;
}
// Start the CAB using the ActionMode.Callback defined above
mActionMode = getActivity().startActionMode(mActionModeCallback);
view.setSelected(true);
return true;
}
});
当您调用startActionMode()时,系统将返回创建的ActionMode。通过将其保存在成员变量中,您可以更改上下文操作栏以响应其他事件。在上面的示例中,ActionMode用于确保在ActionMode实例已经处于活动状态时不会重新创建它,方法是在启动操作模式之前检查该成员是否为null。
在ListView或GridView中启用批处理上下文操作
如果ListView或GridView(或AbsListView的另一个扩展)中有一组项目,并且希望允许用户执行批处理操作,则应该:
- 实现AbsListView.MultiChoiceModeListener接口,并使用setMultiChoiceModeListener()为视图组设置它。在侦听器的回调方法中,您可以指定上下文操作栏的操作,响应操作项上的单击事件,以及处理从ActionMode.Callback接口继承的其他回调。
- 使用CHOICE_MODE_MULTIPLE_MODAL参数调用setChoiceMode()。
例如:
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 invalidate() request
return false;
}
});
现在,当用户选择具有长按的项目时,系统将调用onCreateActionMode()方法并显示具有指定操作的上下文操作栏。当上下文操作栏可见时,用户可以选择其他项目。
在上下文操作提供公共操作项的某些情况下,您可能希望添加允许用户选择项的复选框或类似UI元素,因为它们可能不会发现长按单击行为。当用户选中该复选框时,您可以通过使用setItemChecked()将相应的列表项设置为选中状态来调用上下文操作模式。
创建弹出菜单

固定在右上角的溢出按钮上。
PopupMenu是一个锚定到View的模式菜单。如果有空间,它将显示在锚点视图下方,否则显示在视图上方。它对以下内容很有用:
- 为与特定内容相关的操作提供溢出式菜单(例如Gmail的电子邮件标题,如图4所示)。
注意:这与上下文菜单不同,上下文菜单通常用于影响所选内容的操作。对于影响所选内容的操作,请使用上下文操作模式或浮动上下文菜单。
- 提供命令语句的第二部分(例如标记为“添加”的按钮,该按钮产生具有不同“添加”选项的弹出菜单)。
- 提供类似于Spinner的下拉列表,不会保留持久选择。
注意:PopupMenu可用于API级别11及更高级别。
如果您使用XML定义菜单,则可以在此处显示弹出菜单:
1.使用其构造函数实例化PopupMenu,该构造函数接受当前应用程序Context和菜单应锚定到的View。
2.使用MenuInflater将菜单资源扩展为PopupMenu.getMenu()返回的Menu对象。
3.调用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" />
然后,该活动可以显示如下弹出菜单:
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侦听dismiss事件。
处理点击事件
要在用户选择菜单项时执行操作,您必须实现PopupMenu.OnMenuItemClickListener接口,并通过调用setOnMenuItemclickListener()将其注册到PopupMenu。当用户选择一个项目时,系统会在您的界面中调用onMenuItemClick()回调。
例如:
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显示了一个子菜单,其中的项目可通过单选按钮进行检查。
注意:图标菜单中的菜单项(从选项菜单中)无法显示复选框或单选按钮。如果您选择在图标菜单中选中项目,则必须通过在每次状态更改时交换图标和/或文本来手动指示选中状态。
您可以使用<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()设置检查状态。例如:
@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启动活动(无论它是您的应用程序中的活动还是其他应用程序)。当您知道要使用的意图并具有应该启动意图的特定菜单项时,您可以在适当的on-item-selected的回调方法(例如onOptionsItemSelected()回调)期间使用startActivity()执行intent。
但是,如果您不确定用户的设备是否包含处理意图的应用程序,则添加调用它的菜单项可能会导致菜单项无效,因为意图可能无法解析为活动。要解决此问题,当Android在设备上查找处理您意图的活动时,Android会让您动态地将菜单项添加到菜单中。
要根据接受意图的可用活动添加菜单项:
1.使用CATEGORY_ALTERNATIVE和/或CATEGORY_SELECTED_ALTERNATIVE类别以及任何其他要求定义意图。
2.调用Menu.addIntentOptions()。 Android然后搜索可以执行意图的任何应用程序并将其添加到您的菜单中。
如果没有安装满足意图的应用程序,则不添加任何菜单项。
注意:CATEGORY_SELECTED_ALTERNATIVE用于处理屏幕上当前选定的元素。因此,它只应在onCreateContextMenu()中创建菜单时使用。
例如:
@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:标签中的值作为菜单项标题,将应用程序图标作为菜单项图标。 addIntentOptions()方法返回添加的菜单项数。
注意:调用addIntentOptions()时,它会覆盖第一个参数中指定的菜单组的所有菜单项。
允许您的活动添加到其他菜单
您还可以将活动服务提供给其他应用程序,因此您的应用程序可以包含在其他应用程序的菜单中(反转上述角色)。
要包含在其他应用程序菜单中,您需要像往常一样定义intent过滤器,但请确保包含intent过滤器类别的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>
阅读有关在Intents和Intent Filters文档中编写intent过滤器的更多信息。
有关使用此技术的示例应用程序,请参阅Note Pad示例代码。