4.5 Menu和ActionBar
菜单是人机交互的重要接口,在Android SDK中,提供了菜单类android.view.Menu,以完成与菜单有关的操作。
Android SDK提供三种菜单,分别为:
●Options Menu:又称选项菜单,是Activity的主要菜单项的集合,当用户单击Menu按钮时出现。在Android 2.3以下的版本中,这种菜单最多显示六个带图标的菜单项。当菜单中含有六个以上的菜单项时,弹出菜单将只显示前五个菜单,第六个菜单项会变为More,单击More菜单项后会出现扩展菜单。扩展菜单不支持图标,但支持单选框和复选框。在Android 3.0(API Level 11)及其以上版本中,默认情况下直接弹出的选项菜单不再显示图标。
●Context Menu:又称上下文菜单,是一个悬浮的菜单项列表,当用户单击注册了上下文菜单的组件时出现。上下文菜单不支持菜单图标和快捷键。
●Submenu:又称子菜单,是某个菜单项的扩展,是一个悬浮的菜单项列表。子菜单不支持菜单图标或者嵌套子菜单。
4.5.1 Options Menu
要实现选项菜单的功能,首先需要重载OnCreatOptionsMenu()方法创建菜单,然后通过onOptionsItemSelected()方法对菜单被单击事件进行监听和处理。
创建一个名为MenusDemo的Eclipse Android Project,在该工程中对菜单的相关知识进行学习。
在工程的res目录下创建一个menu目录,用于存放菜单相关的xml文件。在该目录下创建mymenu.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/item1" android:title="@string/menuitem1" android:icon="@drawable/icon01"/> <item android:id="@+id/item2" android:title="@string/menuitem2" android:icon="@drawable/icon02"/> <item android:id="@+id/item3" android:title="@string/menuitem3" android:icon="@drawable/icon03"/> <item android:id="@+id/item4" android:title="@string/menuitem4" android:icon="@drawable/icon04"/> <item android:id="@+id/item5" android:title="@string/menuitem5" android:icon="@drawable/icon05"/> <item android:id="@+id/item6" android:title="@string/menuitem6" android:icon="@drawable/icon06"/> <item android:id="@+id/item7" android:title="@string/menuitem7" android:icon="@drawable/icon07"/> </menu>
mymenu.xml创建了一个具有七个菜单项的菜单,并且通过android:id属性为每个菜单项指定了id,通过android:title属性为每个菜单项指定了显示的菜单项内容,通过android:icon属性指定了每个菜单项的图标。对应的图标文件放置到res/drawable目录下。
为工程MenusDemo创建名为MenusActivity的Activity,将mymenu.xml中定义的菜单设置为MenusActivity的菜单,重载OnCreatOptionsMenu()方法。MenusActivity.java代码如下:
package introduction.android.menusDemo; import android.app.ActionBar; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.TextView; public class MenusDemoActivity extends Activity { private TextView textview; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); textview=(TextView)findViewById(R.id.textview1); } @Override public boolean onOptionsItemSelected(MenuItem item){ // TODO Auto-generated method stub switch(item.getItemId()){ case R.id.item1: textview.setText("item1 selected!"); break; case R.id.item2: textview.setText("item2 selected!"); break; case R.id.item3: textview.setText("item3 selected!"); break; default: break; } return super.onOptionsItemSelected(item); } @Override public boolean onCreateOptionsMenu(Menu menu){ MenuInflater inflater=getMenuInflater(); inflater.inflate(R.menu.mymenu, menu); return true; } }
其中,
public boolean onCreateOptionsMenu(Menu menu){ MenuInflater inflater=getMenuInflater(); inflater.inflate(R.menu.mymenu, menu); return true; }
这几行代码通过MenuInflater. Inflate()方法将menu.xml中的定义的菜单项内容填充到了菜单中。
在OnCreatOptionsMenu()方法中创建菜单时也支持Menu.add()方法,也能达到同样目的。例如:
menu.add(0,itemid,0,item_title);
表示在菜单中添加一个菜单项,该菜单项的id为itemid,菜单项显示的内容为item_title的内容。但是不鼓励使用这种方式,而应该使用xml文件来创建菜单。
运行MenusDemo实例,单击手机的Menu按钮,得到运行效果如图4.35所示。
图4.35 “Menu”按钮运行效果
由运行效果可见,MenusActivity已经根据mymenu.xml文件创建了一个具有七个菜单项的菜单。但是虽然在mymenu.xml文件中为每个菜单项指定了一个图标,但是生成的选项菜单中却并没有图标被显示出来,这是为什么呢?
实例MenusDemo当前的运行环境是Android4.0,其API Level为14。我们先看一下,同样的代码,在API Level 11之前的运行效果。
双击打开AndroidManifest.xml文件,将其中的代码:
<uses-sdk android:minSdkVersion="14" />
改为:
<uses-sdk android:minSdkVersion="9" />
再次运行MenusDemo实例,单击Menu按钮,得到运行效果如图4.36所示。
图4.36 API Level 11之前Menu按钮运行效果
可见运行在早期的API之上的选项菜单效果要更好一些。为什么会出现这种现象呢?其实在Android SDK 3.0之后,就不再鼓励直接使用选项菜单,而是将选项菜单和ActionBar结合使用。
ActionBar又称活动栏,位于Activity的顶部,取代了原来的标题的位置。ActionBar中包含很多ActionItem,相当于选项菜单的菜单项。将选项菜单与ActionBar结合的方法很简单,只要在xml文件中添加一个android:showAsAction="ifRoom"属性即可。该属性表现如果标题栏有空间的话,就将相关的菜单项放置到ActionBar中。如果标题栏空间不足,未能放置到其中的菜单项仍然会以选项菜单的形式出现。
图4.37 ActionBar运行效果
4.5.2 Context Menu
上下文菜单注册到View对象上后,用户长按该View对象可呼出上下文菜单。上下文菜单悬浮于主界面之上,不支持图标显示和快捷键。其使用方法和选项菜单高度相似,只不过创建上下文菜单的方法为onCreateContextMenu(),响应上下文菜单单击事件的方法为onContextItemSelected()。
仍以工程MenusDemo为例,为MenusActivity的视图中的TextView对象添加一个具有两个菜单项的上下文菜单,运行效果如图4.38所示。
图4.38 两个上下文菜单的运行结果
为TextView对象注册上下文菜单的代码如下:
textview=(TextView)findViewById(R.id.textview1); registerForContextMenu(textview);
创建并处理上下文菜单单击事件的代码如下:
public boolean onContextItemSelected(MenuItem item){ // TODO Auto-generated method stub switch(item.getItemId()){ case R.id.item6: Log.i("menu","item6!"); break; case R.id.item7: Log.i("menu","item7!"); break; default: break; } return super.onContextItemSelected(item); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo){ // TODO Auto-generated method stub menu.add(0, R.id.item6, 0, "上下文菜单项一"); menu.add(0, R.id.item7, 0, "上下文菜单项二"); super.onCreateContextMenu(menu, v, menuInfo); }
4.5.3 SubMenu
子菜单可以被添加到其他菜单上,但是子菜单本身不能再有子菜单。使用addSubMenu()方法为MenusActivity的选项菜单添加一个子菜单,运行效果如图4.39所示。
图4.39 添加子菜单的运行效果
实现该子菜单需要重写onCreateOptionsMenu()方法,代码如下:
public boolean onCreateOptionsMenu(Menu menu){ MenuInflater inflater=getMenuInflater(); inflater.inflate(R.menu.mymenu, menu); SubMenu submenu=menu.addSubMenu("子菜单"); submenu.add(0,1,0,"子菜单项一"); submenu.add(0, 2, 0, "子菜单项二"); return true; }
子菜单的事件处理代码在onOptionsItemSelected()中实现。
MenusActivity.java完整代码如下:
package introduction.android.menusDemo; import android.app.ActionBar; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; import android.widget.TextView; public class MenusDemoActivity extends Activity { private TextView textview; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); textview=(TextView)findViewById(R.id.textview1); registerForContextMenu(textview); // setContentView(textview); } @Override public boolean onOptionsItemSelected(MenuItem item){ // TODO Auto-generated method stub switch(item.getItemId()){ case 1: Log.i("menu","submenu item 1 selected"); case R.id.item1: textview.setText("item1 selected!"); break; case R.id.item2: textview.setText("item2 selected!"); break; case R.id.item3: textview.setText("item3 selected!"); break; default: Log.i("menu","other items selected"); break; } return super.onOptionsItemSelected(item); } @Override public boolean onCreateOptionsMenu(Menu menu){ MenuInflater inflater=getMenuInflater(); inflater.inflate(R.menu.mymenu, menu); SubMenu submenu=menu.addSubMenu("子菜单"); submenu.setIcon(android.R.drawable.ic_menu_crop); submenu.add(0,1,0,"子菜单项一"); submenu.add(0, 2, 0, "子菜单项二"); return true; } @Override public boolean onContextItemSelected(MenuItem item){ // TODO Auto-generated method stub switch(item.getItemId()){ case R.id.item6: Log.i("menu","item6!"); break; case R.id.item7: Log.i("menu","item7!"); break; default: break; } return super.onContextItemSelected(item); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo){ // TODO Auto-generated method stub menu.add(0, R.id.item6, 0, "上下文菜单项一"); menu.add(0, R.id.item7, 0, "上下文菜单项二"); super.onCreateContextMenu(menu, v, menuInfo); } }