android menu实现方式有好几种,有时候容易弄混淆,下面来总结一下Menu的几种用法。
一.options Menu
options Menu 就是最常用的菜单,在3.0版本以前,按物理menu键,弹出options menu,在3.0版本以后,则和actionBar结合使用
创建options Menu的方法:
1 定义菜单资源文件
在res/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>
<menu> <item> <group>
一个item表示一个菜单子项,一个group中可以包含若干个item
当一个菜单的条目很多的时候,我们也可以使用子菜单:可以将一个<menu>作为另一个菜单的<item>嵌套
- <?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>
2 要想在Activity中使用菜单资源,必须onCreateOptionsMenu()
方法,该方法主要用于创建菜单
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.game_menu, menu);
- return true;
- }
我们同样也可以使用findItem()和add()方法在代码中创建菜单,在30.版本之前,在用户第一次打开菜单的时候创建菜单,执行该方法,而在3.0以后的版本则是在activity创建的时候就执行该方法,创建菜单。
3 当创建好菜单资源后,就要处理菜单的事件。当用户选择一个菜单之后,包括actionBar之上的action item,系统哦你就会回调onOptionsItemSelected()
方法,然后在该方法中处理点击事件即可:
- @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);
- }
- }
如果在activity中包含fragment,系统会首先调用activity的onOptionsItemSelected()
方法,然后才会点用fragment 的onOptionsItemSelected()
方法,直到有返回true或者调用完所有的onOptionsItemSelected()
方法。
4 很多时候我们需要动态改变菜单的内容,这时候我们应该怎么修改呢?在onCreateOptionsMenu()
,方法中修改吗?上边我们讲过onCreateOptionsMenu()
,方法在创建菜单时候只执行一次,所以该方法显然不合适,应该使用onPrepareOptionsMenu()
方法,2.3版本以前,每次打开菜单的时候都会调用onPrepareOptionsMenu()
方法,在3.0以后的版本上,想要更新菜单,调用该方法,则必须调用invalidateOptionsMenu()
方法,请求系统去调用onPrepareOptionsMenu()
方法。
二.Context Menu
Context menu是一个浮动的列表菜单,要想创建context menu 首先需要相关的View调用registerForContextMenu()注册事件,如果是listView或者gridView的话,可能需要每个item都调用该方法注册事件。
创建菜单,要在Activity或者Fragment中实现onCreateMenu()方法。
- @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);
- }
最后同样也是实现选中或点击事件,实现 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);
- }
- }
三.Contextual Action Mode
contextual Action mode 菜单是对ActionMode的实现,当激活action mode菜单的时候,一个contextual action bar 出现在屏幕顶端的位置,上面显示可以对当前选中条目操作的选项。当用户选择的条目为0,按下 back键,或者选中Action mode菜单左上角的done按钮, action mode 菜单消失。
android官方一般建议以下两种情况下使用并激活action mode菜单
1 一个view的长按事件
2 checkbox选中
要想在自己的应用中使用action mode 菜单,需要以下几个步骤:
1 实现ActionMode.Callback()接口,在方法中要指定contextual action bar 上的操作菜单选项,同时还要实现菜单选项的点击事件。
- 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;
- }
- };
startActionMode()
来激活action mode菜单。
- 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;
- }
- });
要实现
AbsListView.MultiChoiceModeListener接口,在该接口中创建action mode 菜单,指定contextual action bar操作选项,并实现改操作的点击事件和其他回调方法,和ActionMode.Callback()差不多。
通过setMultiChoiceModeListener()注册监听事件
调用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;
- }
- });
四.Pop Menu
Pop menu 总是铆钉在某一个view的下方,如果下方没有地方的话,会在上边或其他的地方。
要想使用pop menu,首先也要定义菜单资源,然后使用PopMenu的构造方法,构造PopMenu需要在构造方法中传入context 和 需要铆钉的View
- public void showPopup(View v) {
- PopupMenu popup = new PopupMenu(this, v);
- MenuInflater inflater = popup.getMenuInflater();
- inflater.inflate(R.menu.actions, popup.getMenu());
- popup.show();
- }
这里需要铆钉的View 就是调用popMenu的Button
- <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" />
PopupMenu.OnDismissListener
.
下一步就是要为popMenu注册点击事件,popup.setOnMenuItemClickListener(this);
处理popMenu的选中事件需要实现PopupMenu.OnMenuItemClickListener
接口。
- @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;
- }
- }