Android 用户界面---菜单(Menus)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在很多类型的应用程序中,菜单是一个常用的用户界面组件。
要提供友好的和前后一致的用户体验,就应该使用Menu APIs把Activity的动作和其他选项展现给用户。
从Android3.0(API 级别11)开始,Android设备不再需要提供一个专用的Menu按钮,随着这种改变,Android应用程序将会从对传统的6项菜单面板的依赖中解脱出来,取而代之的是提供了一个用户展现常用用户动作的操作栏。
尽管针对一些菜单项的设计和用户体验已经改变,但是定义一组动作和选项的语意依然是基于Menu APIs的。
本指南展示了如何创建能够在Android所有版本上演示的三种基本类型的菜单和动作。
选项菜单和操作栏
选项菜单(options menu)是针对Activity的主要菜单集合。
它是你放置应用程序中有全局影响的动作的地方,如“搜索”、“编写电子邮件”、和“设置”等功能。
如果你针对Android2.3或更低的版本来开发应用,那么用户要通过按Menu按钮来展现选项菜单面板。
在Android3.0或更高版本上,源于选项菜单的项目是通过操作栏(action bar)来展现的,它由屏幕上的动作项目和剩余的选项组合而成。
从Android3.0开始,Menu按钮被弃用了(有些设备根本就没有这个按钮),因此,你应该使用操作栏来提供对动作和其他选项的访问。
上下菜单和上下文动作模式
一个上下文菜单是一个当用户在一个元素上执行long-click事件时才显示的浮动菜单。
它提供了影响选择内容或上下文框架的动作。
当给Android3.0和更高的版本开发应用程序时,你应该改用上下文动作模式(contextual action mode)来确保被选内容的动作。
这种模式把影响选择内容的动作项目显示在屏幕顶部的一个横条中,并允许用户选择多个项目。
弹出菜单
一个弹出菜单在一个垂直列表中显示项目的列表,它靠在调用这个菜单的View对象旁边。
它对给相关指定内容提供动作的展现或给一个命令的第二部分提供选项是有好处的。
弹出菜单中的动作不应该直接影响对应的内容,相反,弹出菜单是为了扩展Activity中相关内容区域的动作而设计的。
在XML中定义一个菜单
对于所有的菜单类型,Android提供了标准的XML格式来定义菜单项目。
你应该在一个XML 菜单资源中定义一个菜单和它的所有的项目,而不是在你Activity代码中创建一个菜单。
然后你就能够把菜单资源作为一个Menu对象加载到Activity或Fragment对象中。
由于以下原因,使得使用菜单资源是一个好的实践选择:
1.更容易看清XML文件中的菜单结构;
2.它把针对菜单的内容和应用程序的行为代码给分离开了;
3.它允许你针对不同的平台版本、屏幕尺寸和其他的被应用资源框架利用的配置来创建可
选的菜单配置。
要定义菜单,就要在你的项目内部的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="/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,在用户选择这个菜单项时,应用程序能够用这个ID来识别它。
android:icon
指向一个可描画的资源,用作这个菜单项的图标。
android:title
指向一个用作菜单标题的字符串。
android:showAsAction
指明这个菜单项作为操作栏(action bar)中的一个动作项应该显示的时机和方式。
以上只是你应该使用的最重要的属性,但是还有一些有效的属性。
有关菜单支持的所有属性信息,请看“菜单资源”的文档。
你能够给菜单中的任意一个项目(子菜单除外)添加一个子菜单,通过把<menu>元素作为<item>元素的一个子元素方式来添加。
当应用程序中有很多能够被组织到一个专题中的功能时,子菜单是有益的,就像PC应用程序的菜单栏中的项目(File、Edit、View等)一样,如:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="/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>
要在Activity中使用菜单,你需要使用MenuInflater.inflate()方法来加载菜单资源(把XML 资源转换成可编程对象)。
在下列章节中,你会看到每种类型菜单的创建方法。
创建一个选项菜单
选项菜单应该是包含动作和与当前Activity上下文环境相关的其他选项,如:“搜索”、“编写电子邮件”、和“设置”等。
选项菜单中项目在屏幕上显示的位置依赖与你的应用程序所依赖的Android平台版本:1.如果你的应用程序依赖Android2.3.x(API 级别10)或更低的版本,那么当用户按下Menu
按钮时,你的选项菜单内容会显示在屏幕的底部,如图1所示:当菜单被打开时,首先看到的是图标菜单,它们被六个菜单项持有。
如果你的菜单包含的菜单项目大于6,那么Adroid会放入第六个项目并把其余的项目放到溢出菜单中,用户能够同选择更多的菜单项来打开其余的菜单项。
图1.Android2.3上的浏览器的可选菜单
2.如果你的应用程序依赖Android
3.0(API 级别11)或更高的版本,可先菜单的项目在
操作栏(action bar)中是有效的。
默认情况下,系统会把所有的项目放到动作溢出中,用户能够在操作栏(action bar)的右边看到动作溢出图标(或者,如果Menu按钮有效,按下设备的Menu按钮也可以)。
要让重要的动作快速访问,你能够通过在<item>元素中添加android:showAsAction=”ifRoom”属性设置,把一些菜单项目放到操作栏中显示。
注意:即使你的应用不依赖Android3.0或更高的版本,你也能够构建自己的操作栏(action bar)来模仿类似的效果。
图2.Honeycomb Gallery应用程序的操作栏,显示了导航标签和照相机动作项(被加在动作溢出按钮上)
Honeycomb Gallery应用程序网址:
/resources/samples/HoneycombGallery/index.html
你既可以给Activity子类,也可以给Fragment子类声明选项菜单项目。
如果Activity和Fragment都声明了选项菜单项目,它们会在UI中组合到一起。
Activity的选项菜单会首先显示,紧接着按照每个Fragmeng被添加的顺序来显示Fragment的选项菜单。
如果需要,你能够在每个需要移动的<item>元素中用android:orderInCategory属性来重新指定选项菜单的顺序。
要给一个Activity指定选项菜单,需要重写onCreateOptionsMenu()方法(Fragment也提供它们自己的onCreateOptionsMenu()方法)。
在这个方法中,能够把菜单资源(在XML 文件中定义)加载到这个回调方法提供的Menu对象中。
如:
@Override
public boolean onCreateOptionsMenu(Menu menu){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
你也能够使用add()方法来添加菜单项,并且用findItem()方法获取要用MenuItem APIs 修改属性的菜单项。
如果你的应用程序依赖Android2.3.x或更低的版本,系统会在用户首次打开这个菜单时,调用onCreateOptionsMenu()方法来创建选项菜单。
如果你的应用程序依赖Android3.0或更高的版本,系统会在启动Activity时调用onCreateOptionsMenu()方法,以便把选项菜单显示在操作栏(action bar)中。
处理click事件
当用户选择了选项菜单中的一个菜单项(包括操作栏(action bar)中动作),系统会调用Activity的onOptionsItemSelected()方法。
这个方法把选择的菜单项作为参数来传递。
你能够通过调用getItemId()方法来识别菜单项,这个方法返回了对象菜单项的唯一ID
(这个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)。
如果你Activity包括Fragment,那么系统会首先调用Activity的onOptionsItemSelected()方法,然后会调用每个Fragment的onOptionsItemSelected()方法(按照每个Fragment被添加的顺序),直到其中的一个返回true,或所有Fragment的onOptionsItemSelected()方法都被调用。
提示:Android3.0使用android:onClick属性添加了在XML文件中给菜单项定义on-click 行为的能力。
这个属性值必须是Activity定义的使用菜单的一个方法名。
这个方法必须是公共的,并且要接收一个单一的MenuItem对象参数---当系统调用这个方法时,会用它来传递被选择的菜单项。
更多的信息和示例,请看“菜单资源”文档。
提示:如果你的应用程序包含了多个Activity,并且其中的一些Activity都提供了相同的选项菜单,可以考虑创建一个除onCreateOptionsMenu()和onOptionItemSelected()方法以外没有任何其他实现的Activity类,然后,每个Activity都继承这个Activity,这样就实现了相同选项菜单的共享。
这种方法,你能够只管理一组处理菜单动作的代码,并且每个子类都会继承这个菜单行为。
如果你想要给这个Activity子类添加菜单项,重写那个Activity的onCreateOptionsMenu()方法就可以了,在用menu.add()方法添加新的菜单项时,要调用super.onCreateOptionsMenu(menu)方法,以便初始菜单项被创建。
你也能够给独立的菜单项重写其父类的行为。
在运行时改变菜单项
系统调用onCreateOptionsMenu()方法以后,它会保留你组装的这个菜单的一个实例。
除非这个菜单对某些屏幕是无效的,否则系统不会再次调用onCreateOptionsMenu()方法。
因此,你应该仅在创建初始菜单状态时使用onCreateOptionsMenu()方法,并且在Activity 的生命周期内不使它发生改变。
如果你想要基于Activity生命周期期间发生的事件来修改选项菜单,那么你可以在onPrepareOptionsMenu()方法中来做这件事。
这个方法把当前存在的Menu对象传递给你,以便你能够修改它,如添加、删除、或禁用菜单项。
(Fragment也提供一个onPrepareOptionsMenu()回调方法。
)
在Android2.3.x和更低版本上,每次用户打开选项菜单(按下Menu按钮)时,系统都会调用onPrepareOptionsMenu()方法。
在Android3.0和更高的版本上,当菜单项在操作栏(action bar)中展现的时候,选项菜单被认为是始终打开的。
当一个事件发生,并且你要执行一个菜单更新的动作时,你必须调用invalidateOptionMenu()方法来请求系统调用onPrepareOptionsMenu()方法。
注意:你永远都不会基于当前焦点中的V iew对象来改变选项菜单的项目。
当在触屏模式中,View对象不需要焦点,因此你永远不会使用焦点作为修改选项菜单中菜单项的基础。
如果想要给一个View对象提供一个上下文敏感的菜单,请使用上下文菜单。
创建上下文菜单
上下文菜单提供了影响指定项目或UI中内容结构的动作。
你能够给任何View对象提供一个内容菜单,但是它们最常用于ListView、GridView或集合类型的V iew对象的项目中,用户能够执行每个项目上的动作。
有两个方法来提供上下文动作:
1.在一个浮动的内容菜单中提供上下文动作。
当用户在一个声明支持上下文菜单的View
对象上长按(long-click)时,会显示一个浮动的菜单项目列表(类似一个对话框)。
每次用户能够在一个项目上执行的上下文动作。
2.在上下文动作模式中提供上下文操作。
这种模式是ActionMode类的一个系统实现,它
在屏幕的顶部显示一个带有操作项目的上下文操作栏,这些操作能够影响被选择的项目。
当这种模式被激活,每次用于能够在多个项目上执行一个操作(如果你的应用程序允许)。
注意:上下文操作模式在Android3.0(API 级别11)和以上版本中才是有效的,并且是显示上下文操作的首选技术。
如果你的应用程序支持的平台版本比3.0低,那么就要在这些设备上使用浮动菜单。
浮动上下文菜单(左)和上下文操作栏(右)的截图
创建浮动的上下文菜单
以下是创建浮动的上下文菜单的步骤:
1.通过调用registerForContextMenu()方法把V iew对象注册给被关联的内容菜单,这个方
法接受View对象参数。
如果你的Activity使用一个ListView或GridView对象,并你想给对象中的每个项目都提供相同的内容菜单,可以通过把ListV iew或GridView对象传递给registerForContextMenu()方法来注册一个内容菜单的所有菜单项。
2.实现Activity或Fragment中的onCreateContextMenu()方法。
当被注册的V iew对象接受到一个长按(long-click)事件时,系统会调用你的
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对象,这个对象提供有关选择项目的额外信息。
如果你的Activity有几个View对象,并且每个V iew都提供了一个不同的内容菜单,你可以使用这些参数来判断哪个内容菜单被装载了。
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文件中的每个菜单项分配一个ID值。
当你成功的处理一个菜单项时,会返回true。
如果你没有处理这个菜单项,你应该把这个菜单项传递给父类的实现。
如果你的Activity包含了Fragment对象,Activity会首先接受这个回调。
当未处理时,通过调用父类的回调方法,系统会把这个事件传递每个Fragment对象中的回调方法。
一次一个(按照每个Fragment对象被添加的顺序),直到返回true或false。
(Activity和android.app.Fragment的默认实现都返回false,因此当未处理时,你应该始终调用父类的实现。
)
使用上下文操作模式
上下文操作模式是ActionMode类的一个系统实现,它关注用户跟执行上下文操作的交互。
当用户通过选择一个项目使这种模式成为可能的时候,一个上下文操作栏就会显示在屏幕的顶部,并展现出用户在当前被选择的项目上能够执行的操作。
当这种模式成为可能时,用户
能够选择多个项目(如果应用程序允许),或取消选择项目,并且可继续在Activity内浏览。
当用户取消了所有选择的项目、按下BACK按钮、或选择操作栏左边的“执行”操作时,这种操作模式就会被禁止,并且上下文操作栏也会被隐藏。
注意:上下文操作栏不必跟操作栏关联。
它们独立的操作,上下文操作栏甚至可以显示在操作栏位置之上。
如果你依赖Android3.0(API级别11)或更高的版本,你通常应该使用上下文操作模式来表现上下文操作,而不是浮动内容菜单。
对于那些提供上下文操作的View对象,你通常应该在以下两种事件之上调用上下文操作模式:
1.用户在View对象上执行一个长按(long-click)操作。
2.用户选择了一个复选框或View对象中类似复选框的UI组件。
你的应用程序如何调用上下文操作模式,并给每个操作定义行为,依赖于你的设计。
有以下两种基本的设计:
1.针对个别的、任意的View对象的上下文操作。
2.针对ListView或GridView对象中项目组的批处理上下文操作(允许用户选择多个项目,
并这些选择的项目上执行一个操作)。
针对个别View对象的上下文操作模式
如果你只想在用户选择特定的View对象时,调用上下文操作模式,应该按以下方法来做:1.实现ActionMode.Callback接口。
在它的回调方法中,你能够针对上下文操作栏指定动
作,在操作项目上响应点击事件和处理针对这个操作模式的其他生命周期事件。
2.在显示这个操作栏时,调用startActionMode()方法(如用户长按(long-click)对应的view
对象时)。
如:
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(Context Action Bar)进行各种改变,如用setTitle()和setSubtitle()方法修改标题和子标题(有益于指示有多少项目被选择了)。
我还看到,上例中,当操作模式被销毁时,把mActionMode变量设置为null,接下来,你能看到它是如何被初始化的,以及如何把成员变量保存在你的Activity或Fragment 中。
2.在适当的时机调用startActionMode()方法启用上下文操作模式,如在响应一个V iew对象
的长按事件时:
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对象的实例是否为null,来确保这个对象实例不被重复创建。
在ListView或GridView对象中的批处理上下文操作
如果在ListView或GridView对象(或是另外的AbsListView类的扩展)中有一个项目的集合,并且你想要允许用户对其执行批处理操作,那么你应该按如下的方法做:
1.实现AbsListView.MultiChoiceModeListener接口,并且要用setMultiChoiceModeListener()
方法把它设置给ViewGroup对象。
在这个监听器的回调方法中,你能够给这个上下文操作栏指定动作,响应在操作项目上的点击事件,并且处理从ActionMode.Callback接口中继承来的其他回调方法。
2.调用带有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()方法来调用上下文操作模式。
创建弹出菜单
弹出菜单是停靠在一个View上的一个模式菜单。
如果View对象下方有空间,那么弹出菜单将显示在停靠对象的下方,否则会显示在上方。
这是非常有用的:
1.给指定内容的操作提供一个溢出式菜单(如图4所示的Gmail的邮件头)。
图4. Gmail应用中的一个弹出菜单,停靠于右上角的溢出按钮。
注意:这是跟上下文菜单不一样,上下文菜单是对选择内容有影响的操作。
针对应用选择内容的操作,请使用上下文操作模式或浮动内容菜单。
2.提供命令语句的第二部分(如一个标记为“Add”按钮,用弹出菜单来产生不同的“Add”
选项)。
3.提供一个不保留持久选择的类似Spinner组件的下拉菜单。
注意:弹出菜单是在API 级别11和更高版本上才有效的。
如果你在XML中定义了你的菜单,以下是如何显示弹出菜单的方法:
1.用它的构造器实例化一个PopupMenu对象,它需要当前应用程序的Context和菜单要停
靠的那个View两个对象作为参数。
2.使用MenuInflater对象把你的菜单资源装载到由PopupMenu.getMenu()方法返回的Menu
对象中。
在API 级别14以上的版本,你能够使用PopupMenu.inflate()方法来替代。
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"/>
Activity中的代码:
public void showPopup(V iew 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()回调方法。
如:
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;
}
}
创建菜单组
菜单组是共享某些特性的菜单项目的集合,使用菜单组,可以做以下事情:
1.用setGroupV isible()方法显示或隐藏组内的所有菜单项;
2.用setGroupEnabled()方法启用或禁用组内的所有菜单项;
3.用setGroupCheckable()方法指定所有组内项目是否可复选。
你能够通过把菜单资源中<item>元素嵌套进<group>元素中来创建分组菜单,或者使用带有分组ID的add()方法。
以下是包含了一个分组的菜单资源
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="/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”属性,那么它们将既可以同时显示在操作栏中,也可以同时显示在操作溢出中。
使用可复选的菜单项
菜单能够用于切换选项的界面,针对一个独立的选项使用一个可复选的Checkbox菜单,对于一组互斥的选项可使用一组带有单选按钮的菜单(如图5所示)。
图5.带有复选菜单项的子菜单截图。
注意:图标菜单(选项类型的菜单)中的菜单项不能显示一个复选框或单选按钮。
如果你选择了让图标菜单中的菜单项可复选,那么就必须在每次状态改变时通过更换手动的更换图标或文本来的指明复选的状态。
你能够使用<item>元素中的android:checkable属性给单独的菜单项定义可复选的行为,或者
用<group>元素中的android:checkableBehavior属性给一组菜单项定义可复选行为。
如,下例中菜单组中的每个菜单项都带有一个可复选的复选按钮:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="/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属性可以有以下三种设置:
1.single:菜单组中仅有一个菜单能够被复选(复选按钮)
2.all:所有菜单项都能够被复选(复选框)
3.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);
}
}
如果不用这种方式设置复选状态,那么当用户选择菜单项(复选框或复选按钮)的时候,它的可视状态将不会发生改变。
在你设置这个状态时,Activity会保留菜单的状态,以便用户随后打开这个菜单时,让你设置的复选状态可见。
注意:可复选菜单项打算仅在每个会话的基础上使用,并且在应用销毁之后不保存复选状态。
如果你的应用打算保存用户的设置,你应该使用共享的方式来保存数据。