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);
        }



    }