Android菜单设计(2) : options menu使用注意事项
在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()2. 菜单xml属性
这里只说一个属性,android:enabled=["true" | "false"],对应的方法setEable(boolean)。该属性用来设置菜单是否可用。如下图所示,左边是不可用,右边可用。
其它更加详细的文档,在sdk-path/doc/Dev Guide/Framework Topics/Application Resources/Resource Types/Menu,可以研读一下。
ok,回到主题上来。
3. 工程目录结构
4. 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); } } }
5. 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 [email protected] 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(); } }关于menu,推荐一篇文章:http://www.cnblogs.com/xirihanlin/archive/2010/06/25/1765261.html