菜单Menu的使用
菜单Menu
一.OptionMenu
1.实现步骤
① 在onCreateOptionsMenu(Menu menu)中创建菜单
② 在onOptionsItemSelected(MenuItem item)中点击事件
2.菜单2种创建
① 布局样式进行加载
getMenuInflater().inflate(R.menu.mian_menu,menu);
<item
android:id="@+id/action1" 设置ID
android:title="标题一" 设置标题
android:orderInCategory="80" 设置排序
app:showAsAction="always"> 设置显示方式:always总是显示 never 从不显示 ifRoom有空间就显示
</item>
② 代码实现
menu.add(int groupId, int itemId, int order, CharSequence title);//组号,唯一id,排序(小的在前面),标题
3.属性
id / title / smallIcon必须有的属性
orderInCategory 优先级
showAsAction always(总是显示出来) never(不显示出来) ifRoom(有位置显示) collapseActionView withText
withText withText值示意Action bar要显示文本标题。Action bar会尽可能的显示这个标题,但是,如果图标有效并且受到Action bar空间的限制,文本标题有可能显示不全。
collapseActionView 声明了这个操作视窗应该被折叠到一个按钮中,当用户选择这个按钮时,这个操作视窗展开。否则,这个操作视窗在默认的情况下是可见的,并且即便在用于不适用的时候,也要占据操作栏的有效空间。
一般要配合ifRoom一起使用才会有效果。
二.ContextMenu
1.实现步骤
① registerForContextMenu(View view) 为一个view注册上下文菜单
② onCreateContextMenu() 中生成上下文菜单
③ onContextItemSelected() 中响应上下文菜单项
两种菜单的区别:
OptionMenu的拥有者是Activity,ContextMenu的拥有者是View.
OptionMenu的注意事项
在 Android菜单设计(1) : 使用xml文件布局创建 options menu文章中,初步认识了选项菜单。但是在实际开发中,还是需要注意几个问题,该篇讨论相关问题。
进入正式话题之前,需要了解一些东西。
1. 使用xml方式创建选项菜单
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/new_game"
android:icon="@drawable/ic_new_game"
android:title="@string/new_game" />
<item android:id="@+id/help"
android:icon="@drawable/ic_help"
android:title="@string/help" />
</menu>
需要注意:在使用menu.getItem(int index)方法时,参数index就是您在xml中创建item的顺序,如上面id为new_game的菜单就是index=0的选项,而id为help的菜单就是index=1的选项。
该方法声明:
MenuItem android.view.Menu.getItem(int index)
Gets the menu item at the given index.
Parameters:
index The index of the menu item to return.
Returns:
The menu item.
Throws:
IndexOutOfBoundsException - when index < 0 || >= size()
- 菜单xml属性
这里只说一个
属性,android:enabled=[“true” | “false”],对应的方法setEable(boolean)。该属性用来设置菜单是否可用。如下图所示,左边是不可用,右边可用。
其它更加详细的文档,在sdk-path/doc/Dev Guide/Framework Topics/Application Resources/Resource Types/Menu,可以研读一下。
ok,回到主题上来。
3. 工程目录结构
- Activity代码
package mark.zhang;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.EditText;
public class TestMenuEnableActivity extends Activity {
private MenuItem item_ClearAll = null;
private EditText showInfo = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
showInfo = (EditText) findViewById(R.id.testMenu_edit);
item_ClearAll = (MenuItem) findViewById(R.id.menu_clearAll);
findViewById(R.id.testMenu_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(item_ClearAll != null) {
item_ClearAll.setEnabled(true);
showInfo.setText("it enables item_ClearAll successfully!");
} else {
showInfo.setText("item_ClearAll is Null,it do not enable item_ClearAll!");
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.ui_optionsmenu, menu);
//item_ClearAll = (MenuItem) findViewById(R.id.menu_clearAll);
//item_ClearAll = menu.getItem(0);
return super.onCreateOptionsMenu(menu);
}
```
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.menu_clearAll:
// 清除所有记录
Log.d("mark", "clearAll");
return true;
case R.id.menu_help:
// 帮助
Log.d("mark", "help");
return true;
case R.id.menu_exit:
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
- menu的xml文件
<?xml version="1.0"encoding="UTF-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mymenu">
<item android:id="@+id/menu_clearAll" android:title="清除所有记录"
android:enabled="false" />
<item android:id="@+id/menu_help" android:title="帮助" />
<item android:id="@+id/menu_exit" android:title="退出" />
</menu>
注意:在这里将id为menu_clearAll的菜单设置不可用。在Activity代码中(Button点击事件)将其恢复可用。
运行应用程序,界面如下:
点击test menu,显示结果:
可以发现,使用findViewById方法无法获得菜单实例(MenuItem)对象。然后,我将代码:
item_ClearAll = (MenuItem) findViewById(R.id.menu_clearAll);
放到回调方法onCreateOptionsMenu中,修改如下:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.ui_optionsmenu, menu);
item_ClearAll = (MenuItem) findViewById(R.id.menu_clearAll);
//item_ClearAll = menu.getItem(0);
return super.onCreateOptionsMenu(menu);
}
再次运行,先点击手机的menu按键,确保回调onCreateOptionsMenu从而执行item_ClearAll = (MenuItem) findViewById(R.id.menu_clearAll);效果如下:
然后点击test menu,还是无法创建(MenuItem)对象。汗!
修改回调方法代码,如下:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.ui_optionsmenu, menu);
//item_ClearAll = (MenuItem) findViewById(R.id.menu_clearAll);
item_ClearAll = menu.getItem(0);
return super.onCreateOptionsMenu(menu);
}
可以看出,使用getItem方法创建MenuItem对象。当然,需要先点击menu按键,然后点击test menu,最后再次点击menu按键,才会有如下效果。
呵呵,创建menuItem对象成功,并且菜单已经使能。
6. 思考
使用LayoutInflater的inflate方法,试一试?
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.menu.ui_optionsmenu, null);
item_ClearAll = (MenuItem)view.findViewById(R.id.menu_clearAll);
将上面代码放到回调方法onCreateOptionsMenu或者其它地方,运行之后,报异常:
08-15 06:29:48.195: ERROR/AndroidRuntime(876): Caused by: java.lang.ClassNotFoundException: android.view.menu in loader dalvik.system.PathClassLoader@44c17700
08-15 06:29:48.195: ERROR/AndroidRuntime(876): at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:243)
08-15 06:29:48.195: ERROR/AndroidRuntime(876): at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
08-15 06:29:48.195: ERROR/AndroidRuntime(876): at java.lang.ClassLoader.loadClass(ClassLoader.java:532)
08-15 06:29:48.195: ERROR/AndroidRuntime(876): at android.view.LayoutInflater.createView(LayoutInflater.java:466)
08-15 06:29:48.195: ERROR/AndroidRuntime(876): at android.view.LayoutInflater.onCreateView(LayoutInflater.java:544)
08-15 06:29:48.195: ERROR/AndroidRuntime(876): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:66)
08-15 06:29:48.195: ERROR/AndroidRuntime(876): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:563)
最后,研究了一下源码:
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
if (DEBUG) System.out.println("INFLATING from resource: " + resource);
XmlResourceParser parser = getContext().getResources().getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
parser.close();
}
}
可以看出,该方法一般是用来解析layout文件夹下面的资源文件的。而menu是res下面的一个文件夹,不属于layout。如果注意观察的话,在回调方法onCreateOptionsMenu中,使用:
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.ui_optionsmenu, menu);
来实例化menu这个文件夹。该inflate方法源码:
public void inflate(int menuRes, Menu menu) {
XmlResourceParser parser = null;
try {
parser = mContext.getResources().getLayout(menuRes);
AttributeSet attrs = Xml.asAttributeSet(parser);
parseMenu(parser, attrs, menu);
} catch (XmlPullParserException e) {
throw new InflateException("Error inflating menu XML", e);
} catch (IOException e) {
throw new InflateException("Error inflating menu XML", e);
} finally {
if (parser != null) parser.close();
}
}