理解Android的菜单
       菜单是许多应用程序不可或缺的一部分,Android中更是如此,所有搭载Android系统的手机甚至都要有一个”Menu”键,由此可见菜单在Android程序中的特殊性。Android SDK提供的菜单有如下几种:

       选项菜单:最常规的菜单,android中把它叫做option menu
       子菜单:android中点击子菜单将弹出悬浮窗口显示子菜单项。子菜单不支持嵌套,即子菜单中不能再其他子菜单。
       上下文菜单:android中长按视图控件后出现的菜单,windows点击右键弹出的菜单即上下文菜单
       图标菜单:这个比较简单,就是带icon的菜单项,需要注意的是子菜单项、上下文菜单项、扩展菜单项均无法显示图标。
       选择菜单(alternative menu):用的比较少,以后单独介绍,本文先跳过(其实是我还没弄明白啦o(≧v≦)o~~)
       扩展菜单:选项菜单最多只能显示6个菜单项,超过6个时,第6个菜单项会被系统替换为一个叫“更多”的子菜单,原来显示不下的菜单项都作为“更多”菜单的子菜单项。如下图:

       android.view.Menu接口代表一个菜单,android用它来管理各种菜单项。注意我们一般不自己创建menu,因为每个Activity 默认都自带了一个,我们要做的是为它加菜单项和响应菜单项的点击事件。android.view.MenuItem代表每个菜单 项,android.view.SubMenu代表子菜单。其三者的关系可以用下图来表示


       上面说过,每个activity包含一个菜单,一个菜单又能包含多个菜单项和多个子菜单,子菜单其实也是菜单(因为它实现了Menu接口),因此子菜单也 可以包含多个菜单项。SubMenu继承了Menu的addSubMenu()方法,但调用时会抛出运行时错误。 OnCreateOptionsMenu()和OnOptionsMenuSelected()是activity中提供了两个回调方法,用于创建菜单项 和响应菜单项的点击。


        我们看一下如何通过代码创建和响应最常用的选项菜单(options menu)。

        创建options menu
        之前提到,Android的activity已经为我们提前创建好了android.view.Menu对象,并提供了回调方法 onCreateOptionsMenu(Menu menu)供我们初始化菜单的内容。该方法只会在选项菜单第一次显示的时候被执行,如果你需要动态改变选项菜单的内容,请使用 onPrepareOptionsMenu(Menu)。

java代码:

  1. @Override
  2. public boolean onCreateOptionsMenu(Menu menu) {
  3. // 调用父类方法来加入系统菜单
  4. // 虽然目前android还没有系统菜单,但是为了兼容到以后的版本,最好加上
  5. super.onCreateOptionsMenu(menu);
  6. // 添加菜单项(多种方式)
  7. // 1.直接指定标题
  8. menu.add("菜单项1");
  9. // 2.通过资源指定标题
  10. menu.add(R.string.menuitem2);
  11. // 3.显示指定菜单项的组号、ID、排序号、标题
  12. menu.add(
  13. 1, //组号
  14. Menu.FIRST, //唯一的ID号
  15. Menu.FIRST, //排序号
  16. "菜单项3"); //标题
  17. // 如果希望显示菜单,请返回true
  18. return true;
  19. }
复制代码


       上面的代码演示了添加菜单项的3种方法,下面解释下第三种方法add(int groupId, int itemId, int order, CharSequence title)。其中,第一个参数是组号,android中你可以给菜单分组,以便快速地操作同一组的菜单。第二个参数指定每个菜单项的唯一ID号,你可以 自己指定,也可以让系统来自动分配,在响应菜单时你需要通过ID号来判断哪个菜单被点击了。因此常规的做法是定义一些ID常量,但在android中有更 好的方法,就是通过资源文件来引用,这个之后介绍。第三个参数代表菜单项显示顺序的编号,编号小的显示在前面。

       给菜单项分组

java代码:

  1. @Override
  2. public boolean onCreateOptionsMenu(Menu menu) {
  3. super.onCreateOptionsMenu(menu);
  4. // 添加4个菜单项,分成2组
  5. int group1 = 1;
  6. int gourp2 = 2;
  7. menu.add(group1, 1, 1, "item 1");
  8. menu.add(group1, 2, 2, "item 2");
  9. menu.add(gourp2, 3, 3, "item 3");
  10. menu.add(gourp2, 4, 4, "item 4");
  11. // 显示菜单
  12. return true;
  13. }
复制代码

第一个int类型的group ID参数,代表的是组概念,你可以将几个菜单项归为一组,以便更好的以组的方式管理你的菜单按钮。可以用到的方法有:
removeGroup(id)
setGroupCheckable(id, checkable, exclusive)
setGroupEnabled(id,boolean enabled)
setGroupVisible(id,visible)
个人认为,当你需要在不同场合下显示不同的menu的时候,合理使用这个参数将更为有效的处理菜单的显示。否则一般情况下都归为一组。
第二个int类型的item ID参数,代表的是项目编号。这个参数非常重要,一个item ID对应一个Menu中的选项。在后面使用菜单的时候,就是靠这个item ID来判断,你选中的是哪个选项。
第三个int类型的order ID参数,代表的是菜单项的显示顺序。默认是0,表示菜单的显示顺序就是按照add的顺序来显示。
第四个String类型的title参数,表示选项中显示的文字。

       你可以向上面这样给菜单项分组,分组之后就能使用menu中提供的方法对组进行操作了,如下:
  
java代码:

  1. menu.removeGroup(group1); //删除一组菜单
  2. menu.setGroupVisible(gourp2, visible); //设置一组菜单是否可见
  3. menu.setGroupEnabled(gourp2, enabled); //设置一组菜单是否可点
  4. menu.setGroupCheckable(gourp2, checkable, exclusive); //设置一组菜单的勾选情况
复制代码


        响应菜单项
        android提供了多种响应菜单项的方式,下面一一介绍
        1、通过onOptionsItemSelected方法

        使用的最多方法是重写activity类的 onOptionsItemSelected(MenuItem)回调方法,每当有菜单项被点击时,android就会调用该方法,并传入被点击菜单项。

java代码:

  1. @Override
  2. public boolean onOptionsItemSelected(MenuItem item) {
  3. switch (item.getItemId()) {
  4. //响应每个菜单项(通过菜单项的ID)
  5. case 1:
  6. // do something here
  7. break;
  8. case 2:
  9. // do something here
  10. break;
  11. case 3:
  12. // do something here
  13. break;
  14. case 4:
  15. // do something here
  16. break;
  17. default:
  18. //对没有处理的事件,交给父类来处理
  19. return super.onOptionsItemSelected(item);
  20. }
  21. //返回true表示处理完菜单项的事件,不需要将该事件继续传播下去了
  22. return true;
  23. }
复制代码


       以上代码可作为使用onOptionsItemSelected方法响应菜单的模板来使用,这里为了方便起见将菜单ID硬编码在程序里,你可以使用常量或资源ID来使代码更健壮。

       2.使用监听器
       虽然第一种方法是推荐使用的方法,android还是提供了类似java swing的监听器方式来响应菜单。使用监听器的方式分为两步:

java代码:

  1. //第一步:创建监听器类
  2. class MyMenuItemClickListener implements OnMenuItemClickListener {
  3. @Override
  4. public boolean onMenuItemClick(MenuItem item) {
  5. // do something here...
  6. return true; //finish handling
  7. }
  8. }
  9. //第二步:为菜单项注册监听器
  10. menuItem.setOnMenuItemClickListener(new MyMenuItemClickListener());
复制代码


        3.使用Intent响应菜单        第3种方式是直接在MenuItem上调用setIntent(Intent intent)方法,这样android会自动在该菜单被点击时调用 startActivity(Intent)。但是个人认为与其这样还不如直接在onOptionsItemSelected的case里手动调用 startActivity(Intent)来的直观。

本讲内容:菜单 menu
1、选项菜单 OptionsMenu
2、上下文菜单 ContextMenu
3、子菜单 SubMenu

组成Android用户界面的除了View以外,还有菜单和对话框,这一讲我们就共同学习一下菜单的使用。

菜单是用户界面中最常见的元素,使用也非常频繁,在Android中,菜单被分为如下三种,选项菜单(OptionsMenu)、上下文菜单(ContextMenu)和子菜单(SubMenu),下面分别举例说明。

一、选项菜单 OptionsMenu

Android手机上有个Menu按键,当Menu按下的时候,每个Activity都可以选择处理这一请求,在屏幕底部弹出一个菜单,这个菜单我 们就叫他选项菜单OptionsMenu,一般情况下,选项菜单最多显示2排每排3个菜单项,这些菜单项有文字有图标,也被称作Icon Menus,如果多于6项,从第六项开始会被隐藏,在第六项会出现一个More里,点击More才出现第六项以及以后的菜单项,这些菜单项也被称作 Expanded Menus。

下面我们通过一个例子来学习选项菜单,重要提示都放在代码注释里了,请留意一下。

1、新建一个项目 Lesson16_HelloMenu,主Activity叫 MainHelloMenu.java

2、res\layout\main.xml的内容如下:

<?xml version="1.0" encoding="utf-8"?>

	
	

	
	

3、MainHelloMenu.java的内容如下:

package android.basic.lesson16;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainHelloMenu extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}

	// 点击Menu时,系统调用当前Activity的onCreateOptionsMenu方法,并传一个实现了一个Menu接口的menu对象供你使用
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		/*
		 * add()方法的四个参数,依次是:
		 * 1、组别,如果不分组的话就写Menu.NONE,
		 * 2、Id,这个很重要,Android根据这个Id来确定不同的菜单
		 * 3、顺序,那个菜单现在在前面由这个参数的大小决定
		 * 4、文本,菜单的显示文本
		 */
		menu.add(Menu.NONE, Menu.FIRST + 1, 5, "删除").setIcon(
				android.R.drawable.ic_menu_delete);
		// setIcon()方法为菜单设置图标,这里使用的是系统自带的图标,同学们留意一下,以
		// android.R开头的资源是系统提供的,我们自己提供的资源是以R开头的
		menu.add(Menu.NONE, Menu.FIRST + 2, 2, "保存").setIcon(
				android.R.drawable.ic_menu_edit);
		menu.add(Menu.NONE, Menu.FIRST + 3, 6, "帮助").setIcon(
				android.R.drawable.ic_menu_help);
		menu.add(Menu.NONE, Menu.FIRST + 4, 1, "添加").setIcon(
				android.R.drawable.ic_menu_add);
		menu.add(Menu.NONE, Menu.FIRST + 5, 4, "详细").setIcon(
				android.R.drawable.ic_menu_info_details);
		menu.add(Menu.NONE, Menu.FIRST + 6, 3, "发送").setIcon(
				android.R.drawable.ic_menu_send);
		// return true才会起作用
		return true;

	}

	//菜单项被选择事件
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case Menu.FIRST + 1:
			Toast.makeText(this, "删除菜单被点击了", Toast.LENGTH_LONG).show();
			break;
		case Menu.FIRST + 2:
			Toast.makeText(this, "保存菜单被点击了", Toast.LENGTH_LONG).show();
			break;
		case Menu.FIRST + 3:
			Toast.makeText(this, "帮助菜单被点击了", Toast.LENGTH_LONG).show();
			break;
		case Menu.FIRST + 4:
			Toast.makeText(this, "添加菜单被点击了", Toast.LENGTH_LONG).show();
			break;
		case Menu.FIRST + 5:
			Toast.makeText(this, "详细菜单被点击了", Toast.LENGTH_LONG).show();
			break;
		case Menu.FIRST + 6:
			Toast.makeText(this, "发送菜单被点击了", Toast.LENGTH_LONG).show();
			break;
		}

		return false;
	}

	//选项菜单被关闭事件,菜单被关闭有三种情形,menu按钮被再次点击、back按钮被点击或者用户选择了某一个菜单项
	@Override
	public void onOptionsMenuClosed(Menu menu){
		Toast.makeText(this, "选项菜单关闭了", Toast.LENGTH_LONG).show();
	}

	//菜单被显示之前的事件
	@Override
	public boolean onPrepareOptionsMenu(Menu menu){
		Toast.makeText(this, "选项菜单显示之前onPrepareOptionsMenu方法会被调用,你可以用此方法来根据打当时的情况调整菜单", Toast.LENGTH_LONG).show();
		//如果返回false,此方法就把用户点击menu的动作给消费了,onCreateOptionsMenu方法将不会被调用
		return true;
	}
}

4、运行程序,检查效果:

image

image  
image

image

童鞋们可以留意一下Activity的三个和选项菜单相关的方法的使用。

5、用xml的方式改写上面的例子,在res中新建一个目录menu,在其中建立一个options_menu.xml,内容如下:

<?xml version="1.0" encoding="utf-8"?>

6、更改MainHelloMenu.java的onCreateOptionsMenu()方法,内容如下

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		this.getMenuInflater().inflate(R.menu.options_menu, menu);
		return true;
	}

7、再次运行程序查看结果:

image

两种方法比较,个人感觉还是事先定义好菜单的xml比较好,程序代码部分会比较清晰。

posted on 2011-10-14 09:53  情定诺坎普  阅读(361)  评论(0编辑  收藏  举报