前言
本篇博客讲解一下菜单Menu的使用。菜单在windows应用中使用十分广泛,几乎所有的windows应用都有菜单,Android中也加入了菜单的支持。从官方文档了解到,从Android3.0(API level 11)开始,Android设备不再要求提供一个专门的菜单按钮,转而推荐使用ActionBar。所以现在市面上很多新设备使用三个虚拟按键,并不再额外提供菜单按钮,但是按钮的使用也是有些地方可以借鉴的。
因为Android版本的发展,对于菜单的支持各个版本有很大的区别,而Android3.0是个分水岭,大概可以分为下面三类:
- OptionMenu和ActionBar:一些操作的集合,如果开发的平台在Android3.0之上,推荐使用ActionBar,如果开发的平台在Android2.3或之下,还是可以使用OptionMenu的。
- ContextMenu和ActionMode:ContextMenu是一个浮动的窗口形式展现一个选项列表,ActionMode是一个显示在屏幕顶部的操作栏,允许用户选择多个选项,ActionMode在Android3.0之后才有支持。
- Pupop Menu:PopupMenu是固定在View上的模态菜单,以弹出的方式显示,在Android3.0之后才有支持。
在XML中定义一个菜单
Android提供了标准的XML格式的资源文件来定义菜单项,并且对所有菜单类型都支持,推荐使用XML资源文件来定义菜单,之后再把它Inflater到Activity或者Fragment中,而不是在Activity中使用代码声明。
而菜单的XML资源文件,需要创建在/res/menu/目录下,并且包含一下几个元素:
- <menu>:定义一个Menu,是一个菜单资源文件的根节点,里面可以包含一个或者多个<item>和<group>元素。
- <item>:创建一个MenuItem,代表了菜单中一个选项。
- <group>:对菜单项进行分组,可以以组的形式操作菜单项。
<item>元素除了常规的id、icon、title属性的支持,还有一个重要的属性:android:showAsAction,这个属性是起兼容性的,描述了在Android的高版本中,菜单项何时以何种方式加入到ActionBar中。
<group>是对菜单进行分组,分组后的菜单显示效果并没有区别,唯一的区别在于可以针对菜单组进行操作,这样对于分类的菜单项,操作起来更方便,提供如下的操作:
- Menu.setGroupCheckable():菜单组内的菜单是否都可选。
- Menu.setGroupVisible():是否隐藏菜单组的所有菜单。
- Menu.setGroupEnabled():菜单组的菜单是否有用。
如果菜单项需要单选或者多选,可以使用android:checkableBehavior属性设置,它可以对单个<item>或者<group>设置一个组,这个属性接受三个参数:single,单选;all,多选,none,没有Checked的选项,默认。
当创建好一个XML菜单资源文件之后,可以使用MenuInflater.inflate()方法填充菜单资源,使XML资源变成一个可编程的对象。
OptionMenu
OptionMenu,选项菜单,必须设备具有菜单按钮才可以触发。因为屏幕的限制,最多只能展示六个菜单项,如果定义的菜单项超出了六个,其他的菜单项将被隐藏,第六个菜单将会显示“更多”,点击展开更多的菜单。虽说在Android3.0之后不再推荐使用选项菜单,但是如果使用了,在Android3.0之后的设备上,选项菜单项将被默认转移到ActionBar中,这个可以通过android:showAsAction属性控制。
使用OptionMenu需要在Activity或者Fragment中重写onCreateOptionsMenu(Menu)方法,在这个方法中声明一个选项菜单。菜单的存在是为了提供操作,所以Activity和Fragment中还提供了一个onOptionsItemSelected(MenuItem)方法,用于响应选项菜单中选中的时候的响应。OptionMenu就是操作一个Menu对象和MenuItem对象。
下面通过两个Demo来展示一段选项菜单的使用,分别使用代码声明菜单和XML资源文件声明菜单的方式说明。
声明代码:
1 package com.example.menudemo;
2
3 import android.app.Activity;
4 import android.content.Intent;
5 import android.os.Bundle;
6 import android.view.Menu;
7 import android.view.MenuItem;
8 import android.view.SubMenu;
9 import android.widget.Toast;
10
11 public class OptionMenu1Activitty extends Activity {
12
13 @Override
14 protected void onCreate(Bundle savedInstanceState) {
15 // TODO Auto-generated method stub
16 super.onCreate(savedInstanceState);
17 setContentView(R.layout.activity_optionmenu1);
18 }
19
20 @Override
21 public boolean onCreateOptionsMenu(Menu menu) {
22
23 //直接Add菜单选项到Menu中
24 menu.add(1000, 100, 0, "System menu");
25 //获取添加的菜单选项,然后设置其图标
26 MenuItem menuItem2=menu.add(1000, 101, 1, "User menu");
27 menuItem2.setIcon(R.drawable.ic_launcher);
28 //获取添加的菜单选项,增加一个Intent,点击后转向IntentActivity
29 MenuItem menuItem3=menu.add(1000, 102, 2, "Intent menu");
30 menuItem3.setIcon(R.drawable.ic_launcher);
31 Intent intent=new Intent(OptionMenu1Activitty.this, IntentActivity.class);
32 menuItem3.setIntent(intent);
33
34 //添加一个SubMenu,点击后弹出一个子菜单对话框
35 SubMenu submenu=menu.addSubMenu(1000, 103, 3, "Sub menus");
36 submenu.add(1000, 104, 4, "Sub ment1");
37 submenu.add(1000, 105, 4, "Sub ment2");
38 submenu.add(1000, 106, 4, "Sub ment3");
39 return true;
40 }
41
42 @Override
43 public boolean onOptionsItemSelected(MenuItem item) {
44 boolean flag;
45 switch (item.getItemId()) {
46 case 100:
47 Toast.makeText(OptionMenu1Activitty.this, "selected System menu", Toast.LENGTH_SHORT).show();
48 flag=true;
49 break;
50 case 101:
51 Toast.makeText(OptionMenu1Activitty.this, "selected User menu", Toast.LENGTH_SHORT).show();
52 flag=true;
53 break;
54 case 104:
55 Toast.makeText(OptionMenu1Activitty.this, "selected Sub menu1", Toast.LENGTH_SHORT).show();
56 flag=true;
57 default:
58 flag=super.onOptionsItemSelected(item);
59 break;
60 }
61 return flag;
62 }
63
64 }
实现效果,Android2.3:
使用XML资源文件定义选项菜单,XML资源文件:
1 <?xml version="1.0" encoding="utf-8"?> 2 <menu xmlns:android="http://schemas.android.com/apk/res/android" > 3 4 <item 5 android:id="@+id/item1" 6 android:showAsAction="never" 7 android:title="System menu"> 8 </item> 9 <item 10 android:id="@+id/item2" 11 android:showAsAction="never" 12 android:title="User menu" 13 android:icon="@drawable/ic_launcher"> 14 </item> 15 <item 16 android:id="@+id/item3" 17 android:showAsAction="never" 18 android:title="Intent menu" 19 android:icon="@drawable/ic_launcher"> 20 </item> 21 <group android:id="@+id/group_file" > 22 <item android:id="@+id/menu_save" 23 android:title="menu group save" /> 24 <item android:id="@+id/menu_delete" 25 android:title="menu group delete" /> 26 </group> 27 <item android:id="@+id/file" 28 android:title="Sub menus" > 29 <!-- "file" submenu --> 30 <menu> 31 <item android:id="@+id/sub_menu1" 32 android:title="Sub menu1" /> 33 <item android:id="@+id/sub_menu21" 34 android:title="Sub menu2" /> 35 <item android:id="@+id/sub_menu3" 36 android:title="Sub menu3" /> 37 </menu> 38 </item> 39 </menu>
Java代码:
1 package com.example.menudemo;
2
3 import android.app.Activity;
4 import android.content.Intent;
5 import android.os.Bundle;
6 import android.view.Menu;
7 import android.view.MenuItem;
8 import android.widget.TextView;
9 import android.widget.Toast;
10
11 public class OptionMenu2Activitty extends Activity {
12 private TextView tv;
13 @Override
14 protected void onCreate(Bundle savedInstanceState) {
15 // TODO Auto-generated method stub
16 super.onCreate(savedInstanceState);
17 setContentView(R.layout.activity_optionmenu1);
18 tv=(TextView)findViewById(R.id.tvOptionMenu1);
19 tv.setText("加载XML资源填充Menu");
20 }
21
22 @Override
23 public boolean onCreateOptionsMenu(Menu menu) {
24 // 使用布局文件加载菜单
25 getMenuInflater().inflate(R.menu.optionmenu2, menu);
26 return super.onCreateOptionsMenu(menu);
27 }
28
29 @Override
30 public boolean onOptionsItemSelected(MenuItem item) {
31
32 switch (item.getItemId()) {
33 case R.id.item1:
34 Toast.makeText(OptionMenu2Activitty.this, "selected System menu", Toast.LENGTH_SHORT).show();
35 return true;
36 case R.id.item2:
37 Toast.makeText(OptionMenu2Activitty.this, "selected User menu", Toast.LENGTH_SHORT).show();
38 return true;
39 case R.id.item3:
40 Intent intent=new Intent(OptionMenu2Activitty.this, IntentActivity.class);
41 startActivity(intent);
42 return true;
43 case R.id.menu_save:
44 Toast.makeText(OptionMenu2Activitty.this, "file save", Toast.LENGTH_SHORT).show();
45 return true;
46 case R.id.sub_menu1:
47 Toast.makeText(OptionMenu2Activitty.this, "Selected sub_menu1", Toast.LENGTH_SHORT).show();
48 return true;
49 default:
50 return super.onOptionsItemSelected(item);
51 }
52
53
54 }
55
56 }
效果和使用Java代码声明菜单一样,这里就不再展示了。
ContextMenu
ContextMenu,上下文菜单提供了注册在View组件的菜单操作,它以一个浮动的窗口显示(类似于对话框),当用户长按某被注册了上下文菜单的视图,则触发上下文菜单显示。通常都用于ListView或者GridView等视图集合中。
使用上下文菜单的步骤:
- 使用Activity.registerForContextMenu(View)方法为指定View注册上下文菜单。
- 在Activity或者Fragment中重写onCreateContextMenu()方法,当被注册的视图接受到长按事件后,系统调用onCreateContextMenu()方法,在这个方法中声明上下文菜单。
- 实现onContextItemSelected()方法,用于响应菜单想的选中。
示例,菜单XML资源文件代码:
1 <menu xmlns:android="http://schemas.android.com/apk/res/android" > 2 3 <item 4 android:id="@+id/context_copy" 5 android:orderInCategory="100" 6 android:showAsAction="never" 7 android:title="Copy"/> 8 <item 9 android:id="@+id/context_edit" 10 android:orderInCategory="100" 11 android:showAsAction="never" 12 android:title="Edit"/> 13 <item 14 android:id="@+id/context_delete" 15 android:orderInCategory="100" 16 android:showAsAction="never" 17 android:title="Delete"/> 18 </menu>
Java代码:
1 package com.example.menudemo;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import android.app.Activity;
7 import android.os.Bundle;
8 import android.view.ContextMenu;
9 import android.view.MenuInflater;
10 import android.view.MenuItem;
11 import android.view.View;
12 import android.view.ContextMenu.ContextMenuInfo;
13 import android.widget.AdapterView.AdapterContextMenuInfo;
14 import android.widget.ArrayAdapter;
15 import android.widget.ListView;
16 import android.widget.Toast;
17
18 public class ContextMenu1 extends Activity {
19 private ListView listview;
20 private List<String> dataList;
21 @Override
22 protected void onCreate(Bundle savedInstanceState) {
23 super.onCreate(savedInstanceState);
24 setContentView(R.layout.activity_contextmenu1);
25 listview=(ListView)findViewById(R.id.listView1);
26 dataList=getData();
27 ArrayAdapter<String> adapter=new ArrayAdapter<String>(ContextMenu1.this,android.R.layout.simple_list_item_1, dataList);
28 listview.setAdapter(adapter);
29 //为ListView注册上下文菜单
30 registerForContextMenu(listview);
31 }
32
33 @Override
34 public void onCreateContextMenu(ContextMenu menu, View v,
35 ContextMenuInfo menuInfo) {
36 super.onCreateContextMenu(menu, v, menuInfo);
37 //填充一个XML菜单文件
38 MenuInflater inflater = getMenuInflater();
39 inflater.inflate(R.menu.contextmenu, menu);
40 }
41
42 @Override
43 public boolean onContextItemSelected(MenuItem item) {
44 //获取上下文菜单绑定的AdapterView的额外信息
45 AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
46 switch (item.getItemId()) {
47 case R.id.context_copy:
48 Toast.makeText(ContextMenu1.this, "copy "+dataList.get(info.position), Toast.LENGTH_SHORT).show();
49 return true;
50 case R.id.context_delete:
51 Toast.makeText(ContextMenu1.this, "delete "+dataList.get(info.position), Toast.LENGTH_SHORT).show();
52 return true;
53 case R.id.context_edit:
54 Toast.makeText(ContextMenu1.this, "edit " +dataList.get(info.position), Toast.LENGTH_SHORT).show();
55 return true;
56 default:
57 return super.onContextItemSelected(item);
58 }
59 }
60 //ListView数据
61 public List<String> getData()
62 {
63 List<String> data=new ArrayList<String>();
64 for(int i=0;i<8;i++)
65 {
66 data.add("item"+i);
67 }
68 return data;
69 }
70 }
效果展示,Android4.0:
ActionMode
ActionMode,是一个系统实现的用户交互,当用户使用ActionMode后,选择一个选项,一个上下文操作栏会出现在屏幕的顶端,呈现出用户可以对当前选中项目进行的操作选项。进入这种状态可以通过后退按钮或者调用finish()退出。ActionMode为Android3.0之后的支持,所以在开发3.0之后的应用,推荐使用ActionMode,而不是ContextMenu。
使用ActionMode的步骤:
- 实现ActionMode.Callback接口。在它的回调方法中,可以设置操作的上下文操作栏。
- 在需要显示上下文操作栏的时候,调用startActionMode(ActionMode.Callback)。
ActionMode.Callback是ActionMode定义的一个内部接口,这个接口需要实现下面四个方法:
- boolean onCreateActionMode(ActionMode mode,Menu menu):第一次被创建的时候调用。
- boolean onPrepareActionMode(ActionMode mode,Menu menu):刷新菜单列表的时候被调用,一般使用false即可。
- boolean onActionItemClicked(ActionMode mode,MenuItem item):菜单项被选中的时候被调用。
- void onDestroyActionMode(ActionMode mode):退出或销毁的时候被调用。
示例:
1 package com.example.menudemo;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import android.annotation.SuppressLint;
7 import android.app.Activity;
8 import android.os.Bundle;
9 import android.view.ActionMode;
10 import android.view.ActionMode.Callback;
11 import android.view.Menu;
12 import android.view.MenuInflater;
13 import android.view.MenuItem;
14 import android.view.View;
15 import android.widget.AdapterView;
16 import android.widget.AdapterView.AdapterContextMenuInfo;
17 import android.widget.AdapterView.OnItemLongClickListener;
18 import android.widget.ArrayAdapter;
19 import android.widget.ListView;
20 import android.widget.Toast;
21
22 public class ActionModeMenu1 extends Activity {
23 private ListView listview;
24 private List<String> dataList;
25 private ActionMode mActionMode;
26 @Override
27 protected void onCreate(Bundle savedInstanceState) {
28 // TODO Auto-generated method stub
29 super.onCreate(savedInstanceState);
30 setContentView(R.layout.activity_contextmenu1);
31 listview=(ListView)findViewById(R.id.listView1);
32 dataList=getData();
33 ArrayAdapter<String> adapter=new ArrayAdapter<String>(ActionModeMenu1.this,android.R.layout.simple_list_item_1, dataList);
34 listview.setAdapter(adapter);
35 listview.setOnItemLongClickListener(new OnItemLongClickListener() {
36 @SuppressLint("NewApi")
37 @Override
38 public boolean onItemLongClick(AdapterView<?> parent, View view,
39 int position, long id) {
40 if (mActionMode != null) {
41 return false;
42 }
43 //显示ActionMode
44 mActionMode = startActionMode(mActionModeCallback);
45 //标记选中项的下表
46 mActionMode.setTag(position);
47 //标记ListView为可选状态
48 view.setSelected(true);
49 return true;
50 }
51 });
52 }
53 public List<String> getData()
54 {
55 List<String> data=new ArrayList<String>();
56 for(int i=0;i<8;i++)
57 {
58 data.add("item"+i);
59 }
60 return data;
61 }
62
63 private ActionMode.Callback mActionModeCallback=new Callback() {
64
65 @Override
66 public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
67 //刷新菜单列表的时候被调用,但是一般无需刷新
68 return false;
69 }
70
71 @Override
72 public void onDestroyActionMode(ActionMode mode) {
73 //销毁ActionMode
74 mActionMode = null;
75 }
76
77 @Override
78 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
79 //创建ActionMode
80 //使用资源文件填充
81 MenuInflater inflater = mode.getMenuInflater();
82 inflater.inflate(R.menu.contextmenu, menu);
83 return true;
84 }
85
86 @Override
87 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
88 //获取选项中下表
89 int position=(Integer)mode.getTag();
90 switch (item.getItemId()) {
91 case R.id.context_copy:
92 Toast.makeText(ActionModeMenu1.this, "copy "+dataList.get(position), Toast.LENGTH_SHORT).show();
93 //finish退出ActionMode模式
94 mode.finish();
95 return true;
96 case R.id.context_delete:
97 Toast.makeText(ActionModeMenu1.this, "delete "+dataList.get(position), Toast.LENGTH_SHORT).show();
98 mode.finish();
99 return true;
100 case R.id.context_edit:
101 Toast.makeText(ActionModeMenu1.this, "edit " +dataList.get(position), Toast.LENGTH_SHORT).show();
102 mode.finish();
103 return true;
104 default:
105 return false;
106 }
107 }
108 };
109
110
111 }
效果展示,Android4.0:
PopupMenu
PopupMenu,弹出菜单,一个模态形式展示的弹出风格的菜单,绑在在某个View上,一般出现在被绑定的View的下方(如果下方有空间)。
使用PopupMenu的步骤:
- 通过PopupMenu的构造函数实例化一个PopupMenu对象,需要传递一个当前上下文对象以及绑定的View。
- 调用PopupMenu.setOnMenuItemClickListener()设置一个PopupMenu选项的选中事件。
- 使用MenuInflater.inflate()方法加载一个XML文件到PopupMenu.getMenu()中。
- 在需要的时候调用PopupMenu.show()方法显示。
示例:
1 public void showPopup(View v){
2 PopupMenu popup=new PopupMenu(MainActivity.this, v);
3 popup.setOnMenuItemClickListener(new OnMenuItemClickListener() {
4
5 @Override
6 public boolean onMenuItemClick(MenuItem item) {
7 switch (item.getItemId()) {
8 case R.id.context_copy:
9 Toast.makeText(MainActivity.this, "select copy ", Toast.LENGTH_SHORT).show();
10 return true;
11 case R.id.context_delete:
12 Toast.makeText(MainActivity.this, " select delete ", Toast.LENGTH_SHORT).show();
13 return true;
14 case R.id.context_edit:
15 Toast.makeText(MainActivity.this, " select edit ", Toast.LENGTH_SHORT).show();
16 return true;
17 default :
18 return false;
19 }
20 }
21 });
22 popup.getMenuInflater().inflate(R.menu.contextmenu,popup.getMenu());
23 popup.show();
24 }
效果展示,Android4.0:
总结
以上就讲解了Android下Menu的使用。因为上面的所有示例均在一个项目中完成的,所以有些低版本的操作,需要更改AndroidManifest.xml文件中的最低支持版本,改到8即可。在现在的实际开发中,最好还是使用对高版本只是的ActionBar、ActionMode、PopupMenu比较好。

浙公网安备 33010602011771号