摘要:一直觉得菜单很简单,但是瞧了瞧API文档,才发现菜单还有这么多东西,所以必须得整理一下各个菜单的使用方式,文章主要写菜单的动态添加和通过XML添加,讲解不同类型菜单的特点和使用方法。
============================================
文章结构:
       1. 为什么会有菜单
       2. 菜单的不同创建方法
               2.1 动态创建
               2.2  通过XML资源文件创建
       3.菜单的类型(讲了五种菜单的使用方法)
       4.总结
============================================
1. 为什么会有菜单
       菜单一般是提供一些设置或是软件信息什么的,移动设备的屏幕不像PC那么大,不可能在屏幕搞一些按键来触发一些平时使用不会经常操作的事件,比如设置软件配置,查看软件信息什么的。这些功能可以添加到菜单选项中,既提供了该功能,又不会占用屏幕空间。(纯属扯淡有木有啊!!!因为我实在想不出要以什么开头写这篇总结)
2. 菜单的不同创建方法
2.1 动态创建
       通过重写Activity中的onCreateOptionMenu方法来创建菜单,一般使用menu.add(“选项名”)为添加一个菜单选项, menu.getItem(int itemIndex)则是根据选项的索引获取该菜单选项,并对其进行操作,比如添加点击事件onMenuItemClickListener,用addSubMenu添加子菜单等。
优点:创建方便,不需要建立资源文件。
缺点:对于菜单条目过多或多级菜单操作不方便,按键多添加点击事件不方便。
2.2 通过XML资源文件创建
       可以 通过menu文件夹下的menu.xml创建菜单的样式,然后再利用getMenuInflater().inflate(menuRes, menu)将创建的菜单样式inflate到程序中。大体主要分三步:
第一步:建立XML资源文件:menu.xml文件一般的定义方式见如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<? 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 >
第二步:在onCreateOptionMenu回调函数完成XML资源的infate,把菜单资源文件压入到程序中, 不同菜单使用不同的回调函数,比如ContextMenu使用onCreateContextMenu
1
2
3
4
5
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true ;
}
 第三步:如果我们需要给菜单添加点击事件,一般我们是通过重写onMenuItemSelected来设置的, 不同菜单使用不同的点击回调函数,比如ContextMenu使用onContextItemSelected写法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public boolean onMenuItemSelected( int featureId, MenuItem item) {
switch (item.getItemId()) {
case Item.ID1:
//do something
break ;
case Item.ID2:
//do something
break ;
//......
}
return super .onMenuItemSelected(featureId, item);
}
3. 菜单的类型:
   3.1 普通菜单:
       一般的普通菜单,点击菜单键后显示出来的菜单,使用方法如第二点所述,只是设置item标签时把showAsAction值设为never即可。
   3.2 显示在ActionBar的菜单:
       这样的菜单可以直接从屏幕中看到,不需要点击菜单键才会显示, 要做到这个只需要把Item的showAsAction从never改成ifRoom(如果有空间则显示)或always(总是显示)。例子如下;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
< menu xmlns:android = "http://schemas.android.com/apk/res/android" >
< item
android:id = "@+id/info"
android:orderInCategory = "100"
android:showAsAction = "never"
android:title = "软件信息" >
< menu >
< item android:id = "@+id/authorInfo"
android:title = "软件开发者信息" />
< item android:id = "@+id/versionInfo"
android:title = "软件版本信息" />
</ menu >
</ item >
<!-- 建立一个在Action的菜单选项 -->
< item
android:id = "@+id/settings"
android:orderInCategory = "100"
android:showAsAction = "always"
android:icon = "@drawable/ic_launcher" >
< menu >
< item android:id = "@+id/sysSetting"
android:title = "系统设置" />
< item android:id = "@+id/softSetting"
android:title = "软件设置" />
</ menu >
</ item >
</ menu >
效果图:
003655855.png
   3.3 浮动菜单(属于ContextMenu):
       一般添加到ListView或GridView的菜单, 长按菜单的某一项可以出发浮动菜单,定义这种菜单主要步骤如下:
1、建立一个View,常用的为ListView或GridView;
2、建立XML菜单资源文件;
3、在Activity中的onCreateContextMenu函数中使用getMenuInflater().inflate()方法将XML菜单资源文件压入;
4、在onContextItemSelected回调函数中添加菜单选项的点击事件。
5、使用registerForContextMenu(View)为该View注册ContextMenu;
源码示例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
private ListView list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] listItem = { "1" , "2" , "3" , "4" , "5" };
ArrayAdapter<String> aa = new ArrayAdapter<String>( this ,
android.R.layout.simple_list_item_1, listItem);
list = (ListView) findViewById(R.id.list);
list.setAdapter(aa);
registerForContextMenu(list);  
//为list注册上下文菜单,通过onCreateContextMenu把XML菜单资源文件压进来,
//通过onContextItemSelectd为每个菜单选项添加长按点击事件。
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super .onCreateContextMenu(menu, v, menuInfo);
getMenuInflater().inflate(R.menu.float_menu, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) { //判断长按点击了那个选项,为每个选项添加长按点击事件
case R.id.exit:
showToast( "exit" );
break ;
case R.id.next:
showToast( "next" );
break ;
case R.id.back:
showToast( "back" );
break ;
}
return super .onContextItemSelected(item);
}
private void showToast(String str) {
Toast.makeText(MainActivity. this , str, Toast.LENGTH_SHORT).show();
}
效果图:
003636809.png
   3.4 ActionMode菜单(也属于ContextMenu):
       显示在ActionBar的菜单,这种菜单是用于定义比较重要或常用的功能,放在ActionBar比较显眼。触发这种菜单跟浮动菜单一样,要长按,浮动菜单直接采用注册方法,而 该菜单则需要我们去设置View的长按事件(setOnLongClickListener)。
使用方法:
1、建立XML菜单资源文件;
2、建立一个内部类实现ActionMode.Callback接口,实现该接口的四个函数(onCreateActionMode,onPrepareActionMode,onActionItemClicked,onDestroyActionMode
3、在onCreateActionMode把XML文件压进来,而且返回true!
4、在onActionItemClicked中添加菜单选项点击事件;
5、建立一个View,以Button为例,添加OnLongClickListener事件,事件内容为startActionMode(实现Callback接口的类);
源代码示例:
(1)XML资源文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
< LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:paddingBottom = "@dimen/activity_vertical_margin"
android:paddingLeft = "@dimen/activity_horizontal_margin"
android:paddingRight = "@dimen/activity_horizontal_margin"
android:paddingTop = "@dimen/activity_vertical_margin"
android:orientation = "vertical"
tools:context = ".MenuActivity2" >
< Button
android:id = "@+id/btn_actionMode"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:text = "打开ActionMode菜单" />
< Button
android:id = "@+id/btn_popUp"
android:layout_width = "match_parent"
android:layout_height = "wrap_content"
android:text = "打开PopUp菜单" />
</ LinearLayout >
(2)实现Callback的Java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
private class callback implements ActionMode.Callback {
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.user_info:
Toast.makeText(MenuActivity2. this , "You click user_info" ,
Toast.LENGTH_SHORT).show();
return true ;
case R.id.user_setting:
Toast.makeText(MenuActivity2. this , "You click user_setting" ,
Toast.LENGTH_SHORT).show();
return true ;
case R.id.user_login:
Toast.makeText(MenuActivity2. this , "You click user_login" ,
Toast.LENGTH_SHORT).show();
return true ;
default :
return false ;
}
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
getMenuInflater().inflate(R.menu.menu_activity2, menu);
return true ;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
Log.i( "cth" , "ActionMode is destroyed." );
actionMode = null ;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false ;
}
}
(3)长按事件Java代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
btn_actionMode = (Button) findViewById(R.id.btn_actionMode);
btn_actionMode.setOnLongClickListener( new OnLongClickListener() { //添加长按事件
@Override
public boolean onLongClick(View v) {
if (actionMode != null ) {
return false ;
}
actionMode = startActionMode( new callback());   //开启ActionMode菜单
v.setSelected( true );         //设置为可选
return true ;
}
});
效果图(红框即为ActionMode菜单):
003613859.png
   3.5 Popup弹出菜单:
       该类菜单需要和某个View绑定,当点击该View时在该View的上面或下面(视屏幕空间而定)弹出菜单。
使用方法:
1、建立XML菜单资源文件;
2~5步均可在绑定View的点击事件中实现!
2、建立PopupMenu对象,实例化传入上下文context和绑定的View;
3、使用PopupMenu对象的getMenuInflater().inflate()把XML菜单文件压进来,
4、使用PopupMenu对象自身的setOnMenuItemClickListener设置点击事件;
5、使用PopupMenu对象自身的show显示弹出菜单。
源代码示例:
(1)在View的点击事件中设置2~5步内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
btn_popUp = (Button) findViewById(R.id.btn_popUp);
btn_popUp.setOnClickListener( new OnClickListener() {
@TargetApi (Build.VERSION_CODES.HONEYCOMB)
@SuppressLint ( "NewApi" )
@Override
public void onClick(View v) {
PopupMenu popup = new PopupMenu(MenuActivity2. this , v);   //建立PopupMenu对象
popup.getMenuInflater().inflate(R.menu.menu_activity2,   //压入XML资源文件
popup.getMenu());
popup.setOnMenuItemClickListener(MenuActivity2. this );     //设置点击菜单选项事件
popup.show();                                             //显示菜单
}
});
(2)点击事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.user_info:
Toast.makeText(MenuActivity2. this , "You click user_info" ,
Toast.LENGTH_SHORT).show();
return true ;
case R.id.user_setting:
Toast.makeText(MenuActivity2. this , "You click user_setting" ,
Toast.LENGTH_SHORT).show();
return true ;
case R.id.user_login:
Toast.makeText(MenuActivity2. this , "You click user_login" ,
Toast.LENGTH_SHORT).show();
return true ;
default :
return false ;
}
}
效果图:
003547557.png
4. 总结:
菜单主要分两种,OptionMenu和ContextMenu,只有浮动菜单(floating menu)和ActionMode菜单为ContextMenu。OptionMenu建立菜单的方法为在onCreateOptionMenu中inflate XML文件,在onMenuItemClick中设置点击事件(PopupMenu使用自身的setOnMenuItemClickListener设置),ContextMenu建立菜单的方法为在onCreateContextMenu中inflate XML文件(ActionMode在Callback中),在onContextItemClick中设置点击事件。