概览
默认的,每一个Activity都支持提供多种选择和操作的Menu。你可以增加多个菜单项到定义的菜单中,并且对相应的项进行处理。
增加菜单项最简单的方式是使用MenuInflater注入XML文件。
增加相应菜单项的点击事件最简单的方式是调用onOptionItemSelected(MenuItem)和onContextItemSelected(MenuItem)。
对于不同的menu类型有不同的特性:
1. Context menus(上下文菜单):不支持快捷键和菜单项图标
2. Option menus(选项菜单):不支持检查标记并且只显示。当菜单项多于6个时,会以“更多”来展开显示(expanded menu),展开菜单的菜单项既不显示菜单项图标,也不显示检查标记。
3. Sub menus(子菜单):不支持菜单项图标,也不能嵌套子菜单。
Activity、views、context menus关系图
l Menu相关类的关系图
该关系图说明了一个Menu包括多个menu item,或者多个SubMenu()。
SubMenu类继承至Menu类。
提供两个回调函数:onCreateOptionsMenu()初始化菜单;onOptionsItemselected()对菜单项进行逻辑处理。
l Menu与Activity、views关系图
上下文菜单与选择菜单有些细微的差别。选择菜单属于特定的Activity,而上下文菜单属于特定的View。这就是说,一个Activity有且仅有一个选择菜单,但是可以有多个上下文菜单,因为,每个Activity可以包含多个View,而每个view都可以有自己的上下文菜单;另一个细微的差别是,每个Activity都会自动调用onCreateOptionsMenu()方法,而onCreateContextMenu()不会,只有注册了的View才会。
实例
xml定义菜单
除了在Activity中通过代码来定义菜单外,通过XML资源文件来定义也是一个不错的方式,使用时,你可以在Activtiy中注入定义的菜单资源文件。例如,在工程目录res/menu中建立如下资源文件:
<?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>
需要用到的标签说明:
<menu>必须为根节点,可以包括一个或多个<item>和<group>元素
<item>建立一个菜单项。可以嵌套一个<menu>节点以创建一个子菜单,如:
<?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>
<group>可选的元素。包括多个<item>元素。
创建选择菜单
选择菜单通常用在当前Activity上下文中,如查询、邮件和设置等。值得注意的是,从android 3.0开始(API 11),android平台设备厂商不再提供Menu键,这样开发者需要从传统的6选项面板(Android 2.2)转移到Action bar上来。不过,尽管UI设计与用户体验改变了,但是仍然基于Menu的API。
如果是API 10或者以下版本,当你按下菜单按钮,选择菜单将会出现在屏幕的底部,并且有六个选择项,当多余6个的时候,多余的选择项以“更多”来显示,如图:
如果高于或者等于API 11(Android 3.0)版本,选择项将会显示在action bar。所有的菜单项默认的隐藏右边代表更多项的图标中,点击选项菜单可以弹出选项。为了能够快速访问某个选项,可以在XML资源文件的相应<item>节点中设置android:showAsAction=”ifRoom”。
你可以通过Activity或者Fragment来为选择菜单声明菜单项。如果二者都使用了,它们都将会显示出来,Activity声明的先显示,接着是Fragment的。如果有必要,你可以重新定义菜单项:通过每一个<item>的android:orderInCategory属性。
为某个Activity指明选择菜单,需要覆盖onCreateOptionsMenu()方法(fragments提供它自己的onCreateOptionsMenu()回调函数).例如:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
可以通过add()方法增加菜单项,调用findItem()方法获得菜单项。
处理点击事件
当用户点击选择菜单中的某一项时,系统将触发onOptionItemSelected()函数。可以根据相应的Item 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).
运行时修改菜单项
当系统调用onCreateOptionsMenu()h后,将会保留这个实例,并且将不会再次调用,除非什么原因让该菜单失效。当然,整个Activity生命周期中,你应该仅仅初始化菜单的时候调用onCreateOptionsMenu(),其他时候不再对它做任何改变。
如果如果你需要在Activity生命周期中,基于事件的形式去改变选择菜单,你可以调用onPrepareOptionsMenu()方法来实现,这个方法传递当前已经存在的菜单对象,这样你就可以进行更改的操作,比如增加、移除,或者让某个菜单项失效。
创建取决于上下文的菜单
你可以为任何View提供上下文菜单,但是上下文菜单通常用于ListView、GridView的Item,或者用在其他View集合中的每一项以完成直白的action。
有两种方式提供基于上下文的action:
1. Floating context menu。这是一种漂浮的菜单,当用户长按屏幕时触发。菜单中的每一项同一时刻只有一种基于上下文的响应。
2. Contextual action mode。这种模式是在屏幕的顶端显示一个基于上下文的action bar(高于API 11提供)。
创建漂浮的上下文菜单(floating context menu)
创建一个漂浮的上下文菜单,需要以下几个步骤:
1. 注册。调用registerForContextMenu()方法,传入view参数。
registerForContextMenu(textview);
2. 实现onCreateContextMenu()。当注册了的view获得长按事件时,该函数触发。这个函数中是每个菜单项的定义,通常注入菜单资源文件。例如:
@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);
}
3. 实现onContextItemSelected()。这里是每个Item被点击后的逻辑实现,如:
@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);
}
}
同样的,当某个菜单项处理完后,返回true,否则,返回父类的默认值(false)。