上一篇《Android菜单(一)----关于菜单》http://blog.csdn.net/ljheee/article/details/52334997讲解了菜单相关的基本基础。这篇将讲解Android各种菜单的使用。
Android3.0 开始取消了实体的菜单按钮,引入了操作栏(Action Bar)。
Android5.0将操作栏更名为应用栏(App Bar),目前有以下四种形式的菜单:
• 选项菜单(Optionsmenu)
• 上下文菜单(Contextmenu)
• 上下文操作栏(ContextualAction Bar)
• 弹出菜单(Popupmenu)
类 |
属性 |
描述 |
Menu |
menu |
菜单(在其上添加菜单项,从其中获取菜单项) |
MenuItem |
item |
菜单项(实际点击的控件) |
SubMenu |
menu |
子菜单(只有一级) |
无 |
group |
菜单项可编组,设置 id 标识,用于统一管理:单选、多选、是否可见及可用 |
MenuInflater |
无 |
实例化 res/menu 中的文件为菜单对象 |
public boolean onCreateOptionsMenu(Menu menu):使用此方法调用OptionsMenu 。
public boolean onOptionsItemSelected(MenuItemitem):选中菜单项后发生的动作。
public void onOptionsMenuClosed(Menu menu):菜单关闭后发生的动作。
public boolean onPrepareOptionsMenu(Menu menu):选项菜单显示之前onPrepareOptionsMenu方法会被调用,你可以用此方法来根据打当时的情况调整菜单。
public boolean onMenuOpened(int featureId, Menumenu):单打开后发生的动作。
在 res/menu 目录的 XML 文件中定义菜单项布局,各属性含义如下图:
选项菜单布局文件命名为main_opt_menu.xml,意为“主活动选项菜单”布局文件。代码如下:
xml version="1.0" encoding="utf-8"?> <menu xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/action_about" android:title="About" app:showAsAction="always"/> <item android:id="@+id/action_setting" android:title="Setting" android:icon="@drawable/ic_setting_24dp" app:showAsAction="ifRoom"/> <item android:id="@+id/action_sort" android:title="Sort" android:icon="@drawable/ic_sort" app:showAsAction="always"> <menu> <group android:id="@+id/group_sort" android:checkableBehavior="single"> <item android:id="@+id/action_sort_size" android:title="Size_sort"/> <item android:id="@+id/action_sort_time" android:title="Time_sort"/> <item android:id="@+id/action_sort_type" android:title="Type_sort" /> group> menu> item> menu>
该选项菜单布局文件中,定义了About关于、Setting设置、Sort排序三个菜单项;其中Sort下有3个二级子菜单,并且都放在一个组中,选择模式设为单选android:checkableBehavior="single",即放在一个单选组中,事件响应处理的时候,只可单选。Item的showAsAction:ifRoom(如果有空间则显示)或always(总是显示在操作栏)。
在主活动MainActivity类中,重写onCreateOptionsMenu(Menu menu)方法。
/** * 创建可选菜单 * @param menu * @return */ @Override public boolean onCreateOptionsMenu(Menu menu) { //加载[选项菜单的]布局文件 getMenuInflater().inflate(R.menu.main_opt_menu, menu); return true; }
getMenuInflater().inflate(R.menu.main_opt_menu, menu);方法可加载到我们第一步创建的菜单布局文件main_opt_menu.xml,将会创建一个布局文件中指定的菜单[项]。
boolean isShowSort = true; /** * 预处理 * 设置某些菜单项的属性:可见性,是否可选中 * @param menu * @return */ @Override public boolean onPrepareOptionsMenu(Menu menu) { // menu.findItem(R.id.action_about).setVisible(false); menu.findItem(R.id.action_about).setVisible(isShowSort); return super.onPrepareOptionsMenu(menu); }
通过重写onPrepareOptionsMenu(Menu menu):选项菜单显示之前该方法会被调用,可以预处理某些菜单项是否显示和是否可操作。
/** * 选中菜单项(点击操作栏按钮) * @param item * @return */ @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getGroupId() == R.id.group_sort){ //单选--排序组 item.setChecked(true); } switch (item.getItemId()){ case R.id.action_add: Toast.makeText(MainActivity.this,"Add",Toast.LENGTH_SHORT).show();//显示一条提示信息 break; case R.id.action_search: break; default:break; } return true; }
onOptionsItemSelected(MenuItem item)方法也是只需要在在主活动MainActivity类中重写,实现自己的处理即可。
Android 的上下文菜单类似于 PC 上的右键菜单。当为一个视图注册了上下文菜单之后,长按(2 秒左右)这个视图对象就会弹出一个浮动菜单,即上下文菜单。任何视图都可以注册上下文菜单,不过,最常见的是用于列表视图ListView的item。注意:Android 的上下文菜单不支持图标或快捷键,只能通过长按弹出。上下文菜单很多时候回组合ListView使用。
(1)在Activity活动类创建时(onCreate()方法里),调用 registerForContextMenu() 方法,为视图注册上下文菜单。
(2)重写 Activity 的onCreateContenxtMenu() 方法,调用 Menu 的 add 方法添加菜单项(MenuItem)。
(3)重写 Activity 的onContextItemSelected() 方法,响应上下文菜单菜单项的选中事件。
(1)Activity活动类(ContextActivity.java)
package com.ljheee.menu.androidmenu;
import android.app.Activity;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* Activity活动类
* 实现---上下文菜单
*/
public class ContextActivity extends Activity {
//视图
private ListView listView;
//数据
private List
//适配器
private ArrayAdapter
private int position;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_context);
for (int i = 0; i < 30; i++) {
data.add("数据项 " + i);
}
listView = (ListView) findViewById(R.id.listView_cm);
adapter = new ArrayAdapter
listView.setAdapter(adapter);
// 注册上下文菜单,调用onCreateContextMenu
registerForContextMenu(listView);
// 注销上下文菜单
// unregisterForContextMenu(listView);
}
/**
* 创建上下文菜单
*
* @param menu 菜单
* @param v 注册上下文菜单的视图
* @param menuInfo 菜单信息
*/
@Override
public void onCreateContextMenu(ContextMenu menu,
Viewv,
ContextMenu.ContextMenuInfomenuInfo) {
// 加载菜单文件
getMenuInflater().inflate(R.menu.menu_context, menu);
// 设置菜单标题图标、标题文字
menu.setHeaderIcon(android.R.drawable.ic_menu_edit);
menu.setHeaderTitle("操作");
// 菜单信息:targetView、position、id
AdapterContextMenuInfoinfo = (AdapterContextMenuInfo) menuInfo;
// 列表中触发长按事件(弹出菜单)的位置
position = info.position;
}
/**
* 选中菜单项
*
* @param item 被选中的菜单项
* @return 事件是否已处理完毕(消费)
*/
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit:
doEdit();
break;
case R.id.action_copy:
doCopy();
break;
case R.id.action_remove:
doRemove();
break;
}
return true;
}
@Override
public void onContextMenuClosed(Menu menu) {
super.onContextMenuClosed(menu);
}
private void doRemove() {
showToast("删除 " + data.get(position));
}
private void doCopy() {
showToast("复制 " + data.get(position));
}
private void doEdit() {
showToast("编辑 " + data.get(position));
}
private void showToast(String text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
}
(2)活动对应的布局文件activity_context.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.newer.menu.ContextActivity">
<ListView
android:id="@+id/listView_cm"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
RelativeLayout>
和上下文菜单有些类似,只不过长按选项后,不是弹出浮动菜单,而是出现操作栏,如图。上下文操作栏不跟操作栏关联,它们独立地操作,上下文操作栏甚至可以显示在操作栏位置之上。当用户用长按事件选择一个项目时,系统会调用onCreateActionMode()方法,并显示带有特定操作的上下文操作栏。同时在上下文操作栏显示时,用户还能继续选择其他的项目,即多选。
onCreateActionMode:上下文操作模式第一次被创建时调用。
onDestroyActionMode:当一个上下文操作模式被退出或销毁时调用。
onPrepareActionMode:当一个上下文操作模式的动作菜单无效时,将其重新刷新时调用。
onItemCheckedStateChanged :处于选择模式,一个选项被选择或取消选择时此方法被调用。
onActionItemClicked:用户点击一个动作按钮时调用。
这些都是回调方法,可以直接在Activity活动类中重写。
3、演示:针对ListView或GridView对象中项目组的批处理上下文操作(允许用户选择多个项目,并这些选择的项目上执行一个操作),比如图片、短信的多选删除,就是基于此。
(1)活动类CabActivity.java
package com.ljheee.menu.androidmenu; import android.app.Activity; import android.os.Bundle; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.widget.AbsListView; import android.widget.ArrayAdapter; import android.widget.ListView; import java.util.ArrayList; /** * 活动类 * 演示---上下文操作栏(Contextual Action Bar) */ public class CabActivity extends Activity implements AbsListView.MultiChoiceModeListener { //视图 private ListView listView; //数据 private ArrayListdata = new ArrayList (); //适配器 private ArrayAdapter adapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_cab); listView = (ListView) findViewById(R.id.listView_cab); initData();//初始化数据 // 模版需要有选中状态(activated) adapter = new ArrayAdapter (this, android.R.layout.simple_list_item_activated_1, data); listView.setAdapter(adapter); // 设置选择模式 listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); // 设置多选监听器 listView.setMultiChoiceModeListener(this); } private void initData() { for (int i = 0; i < 30; i++) { data.add("数据项 " + i); } } @Override public void onItemCheckedStateChanged( ActionMode mode, int position, long id, boolean checked) { // 获得选中的总数 int count = listView.getCheckedItemCount(); // 设置标题 mode.setTitle(String.valueOf(count)); // mode.setSubtitle(); } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { // 创建菜单 getMenuInflater().inflate(R.menu.menu_cab, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.action_cab_copy: // 获得选中的多项【稀疏数组】 SparseBooleanArray array = listView.getCheckedItemPositions(); // 适用于有 ID 的数据 // long[] ids = listView.getCheckedItemIds(); break; case R.id.action_cab_remove: break; } // 结束 CAB 模式,调用 onDestroyActionMode 方法 mode.finish(); return true; } @Override public void onDestroyActionMode(ActionMode mode) { } }
(2)活动类对应的布局文件activity_cab.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.newer.menu.CabActivity"> <ListView android:id="@+id/listView_cab" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentTop="true" /> RelativeLayout>
弹出菜单比较简单,使用很灵活,在特定事件触发时,比如点击Button,执行一个响应方法,在这个方法里,就可动态创建菜单,并显示出来。
• 实例化 PopupMenu
• 加载菜单资源文件
• 设置菜单监听器
• 显示菜单
(1)活动类PopupActivity.java
package com.ljheee.menu.androidmenu; import android.app.Activity; import android.os.Bundle; import android.view.MenuItem; import android.view.View; import android.widget.PopupMenu; /** * 活动类 * 演示--弹出菜单 */ public class PopupActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_popup); } public void onClick(View v) { // 创建弹出菜单 // 参数一:上下文 // 参数二:菜单的锚 PopupMenu menu = new PopupMenu(this, v); // 加载菜单文件 menu.inflate(R.menu.menu_popup); // 添加菜单项点击监听器 menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { return true; } }); // 添加菜单消失时的监听器【点击菜单项或其他区域,菜单会消失】 menu.setOnDismissListener(new PopupMenu.OnDismissListener() { @Override public void onDismiss(PopupMenu menu) { } }); // 显示菜单 menu.show(); } }
(2)菜单资源布局文件menu_popup.xml(在res/menu文件夹下,右击res创建Menu)
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.newer.menu.PopupActivity">
<item
android:id="@+id/action_pop_edit"
android:title="编辑" />
<item
android:id="@+id/action_pop_remove"
android:title="删除" />
menu>
完整工程:https://github.com/ljheee/AndroidMenu