菜单在Android开以中是一个比较常见的组件,一般的应用程序都会用到菜单。在Android手机上往往都会存在一个“Menu”的按键,当选择之后会在屏幕的底部显示系统的菜单。在一个菜单中可以包含多个菜单项(MenuItem),一个菜单之中最多只会显示一个2行3列的菜单项,如果菜单项超过了6个,则超出部分会自动隐藏,而且会自动出现一个“更多”的菜单项来提示用户。

在Android系统中,菜单共分为三类:

  • OptionsMenu 选项菜单:按Menu键就会显示,用于当前的Activity
  • ContextMenu 上下文菜单:要在相应的view上按几秒后才显示的,用于view,跟某个具体的view绑定在一起。这类型的菜单不支持icon和快捷键
  • SubMenu 子菜单栏:以上两种menu都可以加入子菜单,但子菜单不能嵌套子菜单,这意味着在Android系统,菜单只有两层,设计时需要注意的!同时子菜单不支持icon。

1、选项菜单OptionsMenu

因为OptionsMenu在屏幕底部最多只能显示6个菜单项,这些菜单项称为IconMenu,IconMenu只支持文字(Title) 以及Icon,可以设置快捷键,不支持Checkbox以及Radio控件,所以不能设置Checkable选项。

而多于6的菜单项会以“More”IconMenu来调出,称为 ExpandedMenu。它不支持Icon,其他的特性都和IconMenu一样! 在Activity里面,一般通过以下函数来使用OptionsMenu: onCreateOptionsMenu (Menu menu) 创建options menu,这个函数只会在menu第一次显示时调用。 onOptionsItemSelected (MenuItem item) 处理选中的菜单项。

创建菜单选项有两种方法: 一.在xml文件中创建.

首先在工程的res目录下面创建一个menu的文件夹,然后在menu文件夹下面创建一个mymenu.xml文件,mymenu.xml里面的具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/id_call"
        android:title="呼叫"
        android:icon="@drawable/ic_menu_call"/>
    <item
        android:id="@+id/id_delete"
        android:title="清除记录"
        android:icon="@drawable/ic_menu_delete"/>
    <item
        android:id="@+id/id_himsg"
        android:title="切换到Q信"
        android:icon="@drawable/ic_menu_himsg"/>
    <item
        android:id="@+id/id_black"
        android:title="加入黑名单"
        android:icon="@drawable/ic_menu_black_list"/>
    <item
        android:id="@+id/id_white"
        android:title="加入白名单"
        android:icon="@drawable/ic_menu_white_list"/>
</menu>

然后在java文件中编码,只要重写onCreateOptionsMenu(Menu menu)这个方法即可创建菜单选项。具体代码如下:

 /**
     * 创建options menu,这个函数只会在menu第一次显示时调用。
     */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		//调用父类方法来加入系统菜单
		// 虽然目前android还没有系统菜单,但是为了兼容到以后的版本,最好加上
	    super.onCreateOptionsMenu(menu);

	    super.getMenuInflater().inflate(R.menu.mymenu, menu);

		// 如果希望显示菜单,请返回true
		return true;
	}

添加事件也只要重写onOptionsItemSelected(MenuItem mi)这个方法即可。具体代码如下:

/**
	 * 当按钮菜单被点击时响应
	 */
	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch (item.getItemId()) {
		case 1:
			Toast.makeText(getApplicationContext(), "你选择的是 呼叫 菜单", 1).show();
			break;
		case 2:
			Toast.makeText(getApplicationContext(), "你选择的是 清除记录 菜单", 1).show();
			break;
		case 3:
			Toast.makeText(getApplicationContext(), "你选择的是 切换到Q信  菜单", 1).show();
			break;
		case 4:
			Toast.makeText(getApplicationContext(), "你选择的是 加入黑名单 菜单", 1).show();
			break;
		case 5:
			Toast.makeText(getApplicationContext(), "你选择的是 加入白名单 菜单", 1).show();
			break;

		default://对没有处理的事件,交给父类来处理
			return super.onMenuItemSelected(featureId, item);
		}
		//返回true表示处理完菜单项的事件,不需要将该事件继续传播下去了
		return true;
	}

二.使用Menu.add()创建菜单选项

首先在定义几个静态的,全局的int型变量,做为菜单的id.然后在onCreateOptionsMenu(Menu menu)这个方法中使用Menu.add()即可添加菜单,具体代码如下:

 /**
     * 创建options menu,这个函数只会在menu第一次显示时调用。
     */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		//调用父类方法来加入系统菜单
		// 虽然目前android还没有系统菜单,但是为了兼容到以后的版本,最好加上
	    super.onCreateOptionsMenu(menu);

	    /**
	     * menu.add(groupId, itemId, order, title)
	     * groupId:菜单项所在的组
	     * itemId:菜单项编号
	     * order:排序
	     * title:标题
	     */
	    menu.add(1,1,1,"呼叫").setIcon(R.drawable.ic_menu_call);
	    menu.add(1,2,2, "清除记录").setIcon(R.drawable.ic_menu_delete);
	    menu.add(2,3,3,"切换到Q信").setIcon(R.drawable.ic_menu_himsg).setEnabled(false);
	    menu.add(2,4,4,"加入黑名单").setIcon(R.drawable.ic_menu_black_list);
	    menu.add(2,5,5,"加入白名单").setIcon(R.drawable.ic_menu_white_list);

		// 如果希望显示菜单,请返回true
		return true;
	}

事件处理与使用xml文件创建菜单一样,这里不再重复。

运行效果如下:

2、上下文菜单 ContextMenu

Android的上下文菜单在概念上和PC软件的右键菜单类似。当一个视图注册到一个上下文菜单时,执行一个在该对象上的“长按”动作,将出现一个提供相关功能的浮动菜单。上下文菜单可以被注册到任何视图对象中,不过,最常见的是用于列表视图ListView的item,在按中列表项时,会转换其背景色而提示将呈现上下文菜单。

为了创建一个上下文菜单,你必须重写这个Activity的上下文菜单回调函数:onCreateContextMenu() 和onContextItemSelected()。在回调函数onCreateContextMenu()里,你可以通过使用一个add()方法来添加菜单项,或者通过扩充一个定义在XML中的菜单资源。然后,通过registerForContextMenu()为这个视图注册一个上下文菜单ContextMenu. 注意:上下文菜单项不支持图标或快捷键。

在下面的这个例子中,我们有一个联系人列表。当单击某一个联系人时,将弹出一个上下文菜单,然后可以对联系人进行操作(本例中只实现了拨号和删除的功能)。

看一下程序的主要代码:

package com.liuzhichao.menu;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import android.app.ListActivity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.SimpleAdapter;
import android.widget.Toast;

public class ContextMenuActivity extends ListActivity {

	// 分别定义通讯录中的用户名、电话、地区等信息
	private String[] info_Names = { "史珍香", "赖月京", "秦寿生", "刘产", "扬伟", "范剑" };
	private String[] info_Phones = { "13844445144", "13844444444",
			"13444445144", "13544445144", "13644445144", "13744445144" };
	private String[] info_Regions = { "火星", "水星", "木星", "月球", "美国", "未知地区" };

	// 定义一个ArrayList数组,每一条数据对应通讯录中的一个联系人信息
	private ArrayList<Map<String, Object>> mInfos = new ArrayList<Map<String, Object>>();

	// 定义一个SimpleAdapter
	private	SimpleAdapter adapter;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		// 添加联系人信息
		for (int i = 0; i < info_Names.length; i++) {
			Map<String, Object> item = new HashMap<String, Object>();
			item.put("img", R.drawable.contact_img);
			item.put("name", info_Names[i]);
			item.put("phone", info_Phones[i]);
			item.put("region", info_Regions[i]);
			mInfos.add(item);
		}

		 adapter = new SimpleAdapter(this, mInfos, R.layout.info,
				new String[] { "img", "name", "phone", "region" }, new int[] {
						R.id.info_img, R.id.info_name, R.id.info_phone,
						R.id.info_region });

		setListAdapter(adapter);

		//为一个列表视图注册上下文菜单
	    registerForContextMenu(getListView());
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v,
			ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, v, menuInfo);

		/**
		 * 这里同样可以通过使用一个menu.add()方法来添加菜单项,
		 * 本例中通过扩充一个定义在XML中的菜单资源
		 */

		MenuInflater flater = getMenuInflater();
		flater.inflate(R.menu.context_menu, menu);
		menu.setHeaderTitle("联系人操作"); //添加标题

	}

	/**
	 * ContextMenu事件处理
	 */
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
		switch (item.getItemId()) {
		case R.id.id_call:
			call(info_Phones[(int)info.id].toString());
			return true;
		case R.id.id_delete:
			deleteUser(info.id);
			return true;
		default:
			return super.onContextItemSelected(item);
		}

	}

	/**
	 *  拨打电话
	 * @param phone  传入电话号码
	 */
   private void call(String phone){
	   Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+phone));
	   startActivity(intent);
   }

   /**
    * “删除”联系人
    * @param id  联系人ID
    */
   private void deleteUser(long id){
	   mInfos.remove((int)id); //这里一定要转换成int

	   //通知adapter数据已变化
	   adapter.notifyDataSetChanged();
   }

}

其中布局文件context_menu.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
     <item
        android:id="@+id/id_call"
        android:title="呼叫"/>
    <item
        android:id="@+id/id_delete"
        android:title="清除记录"/>
    <item
        android:id="@+id/id_himsg"
        android:title="切换到Q信"/>
    <item
        android:id="@+id/id_black"
        android:title="加入黑名单"/>
    <item
        android:id="@+id/id_white"
        android:title="加入白名单"/>
</menu>

在onContextItemSelected() 回调函数中,我们从MenuItem中请求AdapterContextMenuInfo,该对象提供当前选中项的信息。我们从中所要的只是这个选中项的列表ID,然后根据该ID进行相应的操作。

要为一个列表视图中的所有项注册上下文菜单,我们可以传递整个的列表视图对象给registerForContextMenu(View) 方法:

registerForContextMenu(getListView()); 记住,你可以传递任何视图对象来注册一个上下文菜单。这里,getListView()返回这个应用程序的列表活动ListActivity中的列表视图对象。这样,这个列表中的任何item都被注册到这个上下文菜单。

3、子菜单栏 SubMenu

子菜单就是将相同功能的分组进行多级显示的一种菜单。点击子菜单将弹出悬浮窗口显示子菜单项。子菜单不支持嵌套,即子菜单中不能再包括其他子菜单。

创建子菜单的步骤:

  • 1、 覆盖Activity的onCreateOptionsMenu()方法,调用Menu的addSubMenu()方法来添加子菜单
  • 2、 调用SubMenu的add()方法,添加子菜单项
  • 3、 覆盖onContextItemSelected()方法,响应子菜单的单击事件 Android提供了基于Group id管理多个MenuItem的方法。

removeGroup(int group):移除所有属于group的MenuItem。 setGroupEnable( int group ,boolean enable):批量开启或关闭整个组的MenuItem。 setGroupVisible( int group ,visible):批量显示或隐藏整个组的MenuItem。 setGroupCheckable( int group ,boolean checkable,boolean exclusive):设置菜单是否可选中。最后一个exclusive是指是单选还是多选,当exclusive是true时,系统将菜单前面添加单选框,是false时则变成是checkbox多选框。

SubMenu同样支持使用xml创建和编码的方式实现子菜单。下面的例子中直接通过menu.addSubMenu()来添加子菜单:

	/**
     * 创建options menu,这个函数只会在menu第一次显示时调用。
     */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		//调用父类方法来加入系统菜单
		// 虽然目前android还没有系统菜单,但是为了兼容到以后的版本,最好加上
		super.onCreateOptionsMenu(menu);

	    /**
	     * menu.add(groupId, itemId, order, title)
	     * groupId:菜单项所在的组
	     * itemId:菜单项编号
	     * order:排序
	     * title:标题
	     */
	    menu.add(1,1,1,"呼叫").setIcon(R.drawable.ic_menu_call);
	    menu.add(1,2,2, "清除记录").setIcon(R.drawable.ic_menu_delete);
	    menu.add(1,3,3,"切换到Q信").setIcon(R.drawable.ic_menu_himsg).setEnabled(false);
	    menu.add(2,4,4,"加入黑名单").setIcon(R.drawable.ic_menu_black_list);
	    menu.add(2,5,5,"加入白名单").setIcon(R.drawable.ic_menu_white_list);

	    /**
	     * 一个menu可以包括多个子菜单
	     */
	    SubMenu subMenu = menu.addSubMenu(2, 6, 6, "系统设置")
	    		.setIcon(android.R.drawable.ic_menu_more);
	    subMenu.add(1, 2, 2, "网络设置");
	    subMenu.add(1, 3, 3, "高级设置");
	    subMenu.add(1, 4, 4, "安全设置");

	    //设置图标
	    subMenu.setHeaderIcon(android.R.drawable.ic_menu_set_as);
		// 如果希望显示菜单,请返回true
		return true;
	}

这样OptionMenu中多了一项”设置”,

SubMenu
SubMenu

当我们点击的时候,就会出现如下的子菜单。

SubMenu
SubMenu

由于子菜单的事件处理与OptionMeun的事件处理方式一样,这里不再赘述。