menu(菜单)

概述

在许多类型的应用中,菜单是一个常用的用户界面组件。为提供一个熟悉且一致的用户体验,在你的应用中,应该使用Menu API 来呈现用户操作和其它操作。
始于安卓3.0(api 11),安卓机器不再直接提供一个 Menu按钮。安卓应用应该从 依赖于传统的6选项菜单板 迁移到 提供一个action bar 来提高公共的用户操作。
对一些菜单项来说, 尽管 设计和用户体验发生了改变,定义一组操作和选项的语义仍旧是基于 Menu API的。该文件展示了如何创建三种基本类型的菜单和在所有安卓版本上的操作演示:
选择菜单(Options menu)和操作栏(action bar )
          options menu  是activity上的菜单项的主要集合。在这些地方,你应该放置对app有全局影响力的操作,例如   "Search," "Compose email," and "Settings."
         如果你在安卓2.3或更低版本上开发,用户可以通过点击menu按钮来显示选项菜单板。
         在安卓3.0或更高版本,选项菜单上的选项都呈现在action bar上,作为一个联合的显示出来的操作项和溢出选项。从安卓3.0开始,反对使用menu按钮(一些设备上没有),因此你应该迁移到action bar上来提供操作入口和其它选项。
           查看关于 #创建选项菜单(Options Menu) 的相关章节。
上下文菜单(Context menu )和上下文的操作模式( contextual action mode)
         一个上下文菜单是一个浮动菜单(floating menu),当用户执行长按元素动作时出现。它提供影响选中的内容或背景框架的操作。
         在安卓3.0或更高版本开发时, 在选中内容时, 你应该改为使用  上下文操作模式( contextual action mode )来提供操作。该模式 在屏幕顶部的条上 展示影响所选内容的操作项,并允许用户进行多选。
          查看 #创建上下文相关菜单(Contextual Menus) 的相关章节
弹出菜单(Popup menu)
         一个弹出菜单用一个垂直列表展示了一列选项,它停留在一个用来显示菜单的view上。它很好的提供一个涉及特别内容的一些溢出操作 或 提供二级命令选项。弹出菜单中的操作不应该直接影响相关的内容---取决于语境操作。相反,弹出菜单是在你的activity内的相关内容上扩展一些操作。
         查看 #创建弹出菜单(Popup Menu) 的相关章节
对于所有的菜单类型,安卓提供了一个标准的xml格式来定义菜单项。来代替你在activity中使用代码构造,你需要在xml  menu 资源文件夹下定义一个菜单和它的所有的选项。在你的activity或fragment中可以展开该menu资源文件(通过一个menu 对象加载)。
使用差点资源文件是一个好的实践,原因如下:
  • 在XML中容易看清菜单结构
  • 你的应用行为代码和菜单内容分离了开来
  • 允许你为 不同的版本,不同大小的屏幕,和不同的结构来创建不同的菜单
为定义该菜单,在你的 res/menu/ 文件夹下创建一个XML文件,并且使用如下元素构造该菜单:
<menu>
定义一个menu,它是一个菜单项的容器。一个<menu>元素必须是文件的根节点,可以容纳一个或多个<item>和<group>元素。
<item>
创建一个menuItem,它代表一个简单的菜单项。该元素可以包含一个嵌套的<menu>来创建一个子菜单。
<group>
可选项,<item>元素的不可见容器。它允许你将菜单项分类这样就可以分享属性,如活动状态和可见性。更多信息,请看【下文】的相关章节
这里有个menu的例子,命名为 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>元素提供的一些属性可用来定义一个项目的外观和行为。在上面item使用的属性如下:
android:id
一个唯一指向该项的资源ID,当用户选择它时,允许应用识别出该项。
android:icon
一个drawable的引用,用来绘制菜单项的icon
android:title
一个string的引用,用来作为菜单项的title
android:showAsAction
具体说明,何时或如何在action bar上作为action item 来显示该菜单项。
这些就是你需要使用的最重要的属性,但还有更多的可用属性。更多它支持的属性请查看 Menu Resource  文档。
你可以在任何菜单的item(除了子菜单)中添加一个子菜单,通过添加<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>
在你的activity 中使用菜单,你需要使用   MenuInflater.inflate() 展开该菜单资源文件(将xml 资源转换为可编程的对象)。在下面的章节,你会看到如何展开各种类型的菜单。
选项菜单 是一个包含 了当前活动相关内容的操作和其它选项的地方,例如   "Search," "Compose email," and "Settings."
你的选 项菜单在何处显示取决于你安卓的版本:
如果在安卓2.3.x (API 10)或更低版本开发,当用户点击Menu 按钮时,你的选项菜单的内容显示在屏幕的底部,如图1所示。打开时,第一个显示出来的是icon菜单,其中有六个菜单项。如果你的菜单包括的菜单项超过六个,安卓只放置六个项目,其它的放入溢出菜单,可以通过选择more菜单项打开。
如果你在安卓3.0(API 11)或更高版本上开发,选项菜单中的项目会在action bar上应用。默认的,系统放置了所有的项目在溢出菜单栏,用户可以点击在action bar 右部的溢出菜单按钮来显示(或者通过点击设备的menu 按钮,如果可用的话)。为了能够快速使用重要的操作,你可以 中提升少数项目显示在 在action bar中,通过在相应的<item >元素中添加 android:showAsAction="ifRoom"。
更多关于action items 和其它action bar 的行为,请看 Action Bar  导航。
注:尽管你不在安卓3.0或更高版本上开发,你可以构造自己的action bar 布局来实现相似的效果。例如如何支持老版本的安卓上使用 action bar ,看   Action Bar Compatibility  示例。

可以从你的activity 子类或fragment 子类中声明你的选项菜单的选项。如果你在activity 和fragemen 中都声明了选项菜单项,它们会联合显示在UI上。先显示activity的item ,然后就是按加入顺序显示每个fragment 的item 。如果需要,你可以在每一个<item>中添加 android:orderInCategory  属性来对item 重新排序。
为activity 指定一个选项菜单,重写 onCreateOptionsMenu()  (fragment 提供了 onCreateOptionsMenu()回调方法 )。在该方法中,你可以解析你的菜单资源文件(在XML中定义)到 Menu 中,该menu由回调函数提供。如下:
   
   
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.game_menu, menu);
return true;
}
你可以使用 add()  来添加菜单项,使用 findItem()获得item的引用来修改item 的属性,这些方法都在 MenuItem  APIs.中。
如果你在安卓2.3.x和更低版本上开发, 当用户第一次打开菜单时, 系统调用 onCreateOptionsMenu() 来创建选项菜单。如果你在安卓3.0和更高版本上开发,当activity 启动,系统调用 onCreateOptionsMenu(),为了在action bar 中显示item 。

处理点击事件

当用户从你的选项菜单中选择一个项目时(包括actin bar 中的action item ),系统调用你activity 中的 onOptionsItemSelected()  方法。该方法传递了被选中的menuItem。你可以通过调用 getItemId()来识别item,该方法返回一个菜单项的唯一ID(通过资源文件下的 android:id  或在 add() 方法中给定的integer数据 定义 )。你可以匹配这个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 ,系统首先调用activty 中的 onOptionsItemSelected(),然后是每一个fragment (根据fragment 添加的顺序)直到一个返回true 或者所有的fragment 都被调用。
技巧:安卓3.0添加了在xml文件中为菜单项定义on-click 事件的能力,使用 android:onClick  属性。该属性的值必须和在使用该菜单的activity 中定义的方法名相同。方法必须为public 并且接受一个简单的 MenuItem参数——当系统调用该方法时,该参数传递的是被点击的菜单项。更多信息和示例,查看 Menu Resource  文档。
技巧:如果你的应用包含多个activity ,并且其中的一些提供了相同的选项菜单,考虑创建一个activity除了 onCreateOptionsMenu() and  onOptionsItemSelected()  方法之外,什么方法都不去实现。然后让每个可能有相同选项菜单的activity 都继承该类。这样,你可以组织一个代码集合来处理菜单操作和每一个子类的菜单行为。如果你想在每个子类中添加菜单项,在相应的activity 中覆盖 onCreateOptionsMenu()  activity 调用 super.onCreateOptionsMenu(menu)  这样原始的菜单项就被创建了,然后通过 menu.add()  添加新的菜单项。你也可以为每一个菜单项覆盖父类的行为。

在运行时更改菜单项

在系统调用 onCreateOptionsMenu()之后,它保留一个menu的引用并且不在调用 onCreateOptionsMenu(),除非一些原因使得菜单无效。然而,你可以使用 onCreateOptionsMenu()只用来创建初始菜单状态,并且在activity生命周期内不会发生改变。
如果你想在activity生命周期内基于事件来更改菜单选项,你可以在 onPrepareOptionsMenu()  方法中做些什么事情。该方法传递你的menu对象作为当前状态,所以你可以更改它,例如增加,移除或取消items(fragments 提供了 onPrepareOptionsMenu() 方法
在安卓2.3.x和更低版本,每次用户打开选项菜单时(按下menu按钮),系统将会调用 onPrepareOptionsMenu()  
在安卓3.0和更高版本,选项菜单认为是经常被开启的,当菜单项在action bar上显示时。当一件事件发生并且你希望执行一个菜单的更新,你必须调用 invalidateOptionsMenu()  来请求系统调用 onPrepareOptionsMenu() .
:你不该在view获得焦点的时候改变选项菜单上的选项。当在触摸模式(用户没有使用轨迹球或方向键),view不能获取焦点,因此你不应该使用焦点作为在选项菜单中更改选项的基础。如果你想在上下文相关的view中提供菜单项,使用   Context Menu .

一个上下文相关菜单提供了影响 特别项或UI中上下文frame 的操作。你可以为任何view提供一个上下文菜单,但是它们通常被用在 ListView GridView other  或其它 可集合的view上,这样用户可以为每个项目直接执行操作。
两个方法提供一个上下文相关操作:
在浮动上下文菜单( floating context menu )中.菜单显示在一个浮动列表中(和dialog相似)当用户在 被声明提供一个上下文菜单的 view上执行长按操作时,菜单就会显示。此时用户可以在一个选项中执行一个上下文相关操作。
在上下文操作模式( contextual action mode )中.该模式是系统实现的一个 ActionMode 在屏幕的上方 展示了一个上下文相关的action bar ,在该action bar上的选项可以影响被选择的项。当该模式开始工作,用户可以一次执行多个选项操作(如果你的应用允许)
:上下文操作模式在安卓3.0和更高版本上可用,这是个显示上下文相关操作的更好技巧。如果你的应用版本在3.0及其以下,你可以后退到一个浮动上下文菜单。

创建浮动上下文菜单(floating context menu )

为提供一个浮动上下文菜单:
1.注册一个view,上下文菜单通过调用 registerForContextMenu()  并且传递这个view。
     如果你的activity使用了 ListView  或 GridView  并且你想要为每一项都提供相同的上下文菜单,通过调用 registerForContextMenu() .传递该   ListView  or  GridView  来在上下文菜单中注册所有的项目。
2.在你的 Activity  或 Fragment .中 实现 onCreateContextMenu()  方法。当被注册的view接受到一个长按事件,系统调用你的 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,并且都提供了不同的上下文菜单,你或许要使用这些参数来决定展开哪个上下文菜单。
    当用户选择了一个菜单项,系统调用该方法让你执行相应的方法。如下:
   
   
@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  属性来指定,如在 #在XML文件中定义菜单 中展示的一样。
当你成功的处理了菜单项,返回 true 。如果没有处理,应该将它传递到父类的实现中去。如果你的activity中包含了fragments,activity先收到该调用。没有处理时才调用父类实现,系统传递该事件给每个fragment中回调函数,一次一个(按照添加的顺序),直到返回true或false。(activity和fragment默认返回false,因此当没有处理时,你应该经常调用父类)

使用上下文相关操作模式(contextual action mode)

上下文相关操作模式是系统提供的一个 ActionMode,用来集中用户交互并执行相关操作。当用户通过选择一个选项来使用该模式,一个上下文相关的action bar(contextual action bar   CAB)显示在屏幕的顶部,来呈现用户可选择的操作项目。当使用该模式时,用户可选择多个项目(如果你允许),取消选中项,和在activity中持续导航(如果你愿意的话)。该操作模式有缺陷,当用户取消选中所有项时 该上下文相关action bar会消失,按下BACK按钮,或选择在bar左部的Done操作。
:上下文相关action bar 与action bar不相关。他的操作是独立的,尽管contextual action bar 在显示上占据了action bar的位置。
如果你在安卓3.0(API 11)或更高版本开发,你应该经常使用contextual action 模式来提供contextual actions,而不是 浮动上下文菜单。
对于提供上下文操作的view,你应该经常在一个或两个事件上唤醒contextual action 模式:
  • 用户在view上常按
  • 用户在view上选择一个多选框或与之相似的ui组件
如何让你的应用唤醒contextual action 模式并为每个action定义行为 取决于你的设计。这里有两个基本的设计:
  • 在特别的view上使用contextual actions
  • ListView 或GridVieitems 上的一组项目(允许用户多选和执行所有的操作)。
下面的章节描述了每一步骤的需求。
为特别的view使用上下文操作模式
如果你想要唤醒上下文操作模式,仅仅当用户选择一个特别的view时,你需要:
1.实现 ActionMode.Callback  接口。在它的回调方法中,你可以为contextual action bar 指定操作,响应action item的点击事件,并且处理其它生命周期事件。
2.调用 startActionMode()  当你想展示bar时(例如当用户长按该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;
}
};
注意这些事件回调几乎和 options menu ,的回掉差不多,除了每个都传递了与事件相关的 ActionMode 对象。你可以使用 ActionMode  api为CAB来制作不同的变化,如 使用 setTitle()  和 setSubtitle() 修改标题和副标题(指明多少项被选择了)。
也需要注意上面的示例设置了 mActionMode  variable  变量为null,当action mode销毁时。下一步,你会看见它是如何初始化和保存你activity或fragment中可用的成员变量的。
2.适当的时候调用 startActionMode() 来使用contextual action 模式,如在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。将这些存储在一个成员变量中,你可以为上下文相关action bar响应其它事件而做出相应的改变。在上面的示例中,该 ActionMode 被用来确保该 ActionMode  引用没有被重复创建,通过在启动action mode前检查成员是否为空。
在ListView 或GridView 中实现一组上下文相关操作
如果你在一个 ListView  或 GridView  (或其它继承自 AbsListView )中有一组选项,并且允许用户执行一组操作,你应该:
实现 AbsListView.MultiChoiceModeListener 接口并且通过 setMultiChoiceModeListener() . 为view group 进行设置。在监听器的回调函数中,你可以为contextual action bar 指定操作,响应项目的点击事件,并且处理其它继承自 ActionMode.Callback  接口的回调。
调用 setChoiceMode() 并包含 CHOICE_MODE_MULTIPLE_MODAL参数。
例子:
   
   
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()方法并用指定的操作展示contextual action bar 。当cab可见时,用户可以选择额外的项目。
在一些情况下,上下文相关操作提供公共的操作项,你或许想添加一个复选框或允许用户选择项目的这类UI,因为他或许不会发现长按行为。当用户选择了该复选框,你可以通过设置各自列表项的选择状态 setItemChecked()  来唤醒上下文相关模式。


一个PopupMenu是一个停靠在view上的模型菜单。它显示在停靠view 的下方,如果有空间,或者在view上方。它通常用于:
为操作提供一个溢出风格的菜单,涉及特别的上下文(如   Gmail'的电子邮件头,图4所示 )。
:这和context menu 不相同,它的操作通常会影响被选择的内容。操作影响被选择的内容,使用 contextual action mode  或   floating context menu .
为公共语句提供第二部分(如一个被标记为"Add"的按钮产生一个弹出菜单来提高不同的“Add ”操作)
提供一个与 Spinner  相似的 下拉,但并不保留永久性的选项。
:弹出菜单在API 11或更高版本可用。
如果你在XML文件中定义你的菜单,这里教你如何显示该弹出菜单:
1.通过构造器实例化一个 PopupMenu  ,带有当前应用的 Context和应该停靠的 View
2. 使用 MenuInflater  来展开你的菜单资源到 Menu 对象中去,该对象通过 PopupMenu.getMenu()获得。在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(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 .来监听该消失事件。

处理点击事件

当用户选择一个菜单项时,要完成一个操作,你必须实现 PopupMenu.OnMenuItemClickListener 接口并且使用 PopupMenu 通过调用 setOnMenuItemclickListener() 注册它。当用户选择一个项目,系统调用你的 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;
}
}

创建菜单组(Menu Groups

菜单组是一个菜单项的集合,用来共享某些特性。有一个组,你可以:
你可以在你的菜单资源文件中通过在 <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"  ,他们要么同时显示在action bar 要么同时出现在溢出菜单。

使用可选择菜单项(checkable menu items )


一个菜单可被作为交界面来选择开启和关闭选项,使用一个多选框作为一个独立的选项,或者一组相互独立的单选框。图5展示了一个含有选项的替代菜单(submenu ),通过单选按钮进行选择。
:在图标菜单(Icon Menu)中的菜单项(来自选项菜单)无法展示一个复选框或单选按钮。如果你选择在图标菜单中制作选项,你必须通过图标或文字的每次状态改变来人工的指示选择状态。
你可以在 <item>  元素中使用 android:checkable  属性来定义每个菜单项的chekcable行为,或者在 <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>  the  元素中使用 android:checked  属性来指定一个默认选中项,或者在代码中的 setChecked()方法改变选择状态。
当一个可选项被选中时,系统调用你各自的item-selected 回调方法(如 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保存项目的选中状态以便于之后用户打开菜单,你设置的选中状态将可见。
:可选择菜单项仅仅打算用在每个会话上,并且当应用销毁时被保存。如果你的应用设置了需要为用户保存信息,你应该使用 Shared Preferences .来存储该数据。

 基于Intent添加菜单项

有时候你会让一个菜单项通过使用 Intent 去启动一个activity(在你应用 或其它应用 中的activity)。当你知道何时使用该Intent并且有一个特别的菜单项来初始化该Intent,在适当的项目点击(on-item-selected,例如 onOptionsItemSelected()回调 )回调函数中你可以通过 startActivity() 来执行该Intent。
然而,如果你不确定用户的设备中是否有intent要启动的应用,那么需要添加一个菜单项,一个没有任何功能的菜单项,因为该intent或许不决定启动一个activity。为解决这个问题,安卓允许你在你的菜单中动态的添加菜单项,当安卓系统在设备中找到了你Intent需要启动的activity时。
基于intent接受的可用activity来添加菜单项:
1.定义一个intent并带有 CATEGORY_ALTERNATIVE 和/或 CATEGORY_SELECTED_ALTERNATIVE,加上任何需求。
2.调用 Menu.addIntentOptions() .。安卓系统之后会寻找符合intent的应用并且将它们加入你的菜单。
如果没有符合的应用,便没有菜单项被添加。
CATEGORY_SELECTED_ALTERNATIVE   used  被用来处理屏幕上的当前选中元素。因此,只有当在 onCreateContextMenu() .中创建一个menu时才被使用。
如下:
   
   
@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;
}
对于每一个发现的符合条件的activity,添加一个菜单项,在intent过滤器中使用 android:label  作为菜单项的标题,应用图标作为菜单项的图标。 addIntentOptions()方法返回被添加的菜单项的数量。
:当你调用 addIntentOptions(),它重写所有的 在第一个参数传过来的菜单组中的 菜单项。

 允许你的activity被加到其它菜单上

你可以 提供 让 你的activity添加到其他应用中 的服务,这样你的应用可以在别的菜单上被包含(与上文描述的任务相反)。
为了能够被包含进别的应用菜单,你通常需要定义一个intent 过滤器,但是确保包含了 CATEGORY_ALTERNATIVE  and/or  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>
更多关于intent 过滤器的信息,请查看 Intents and Intent Filters  
一个使用这些技术的示例代码 ,请查看   Note Pad 示例代码






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值