7. 自定义菜单和动作

7.1 问题

应用程序需要为用户提供一个动作集,但又不想占用视图结果的屏幕空间。

7.2 解决方案

(API Level 7)
使用框图中的选项菜单功能在Action Bar内提供常用动作,以及在溢出的弹出式菜单中提供额外的选项。此外,通过使用PopMenu,可以将菜单附加到现有的视图并显示为浮动下拉菜单。此功能用于在应用程序中除了ActionBar之外的任意位置放置菜单,但在用户需要这些菜单之前使它们保持脱离视图。
根据设备平台的版本的不同,Android的菜单功能也有所不同。在早期的版本中,所有的Android都有一个物理的MENU键可以触发这个功能。从Android3.0开始,出现了没有物理按钮的设备,菜单功能也变成了ActionBar的一部分。
驻留在ActionBar中的动作项还可以展开以显示称为动作视图的自定义小部件。这可以用于提供搜索字段等功能,该功能需要额外的用户输入,但要将其隐藏在某个动作项的后面,直到用户点击时才会显示。

注意:
该例使用来自Android支持库的一些兼容类来向后兼容运行Android 2.1 (API Level 7)的设备。关于在项目中包括支持库的更多信息,请参阅http://developer.android.com/tools/support-library/index.html。

7.3 实现机制

以下代码清单定义了将在XML中使用的选项菜单。

res/menu/options.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:appcompat="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/menu_add"
        android:title="Add Item"
        android:icon="@android:drawable/ic_menu_add"
        appcompat:showAsAction="always|collapseActionView"
        appcompat:actionLayout="@layout/view_action" />
    <item android:id="@+id/menu_remove"
        android:title="Remove Item"
        android:icon="@android:drawable/ic_menu_delete"
        appcompat:showAsAction="ifRoom" />
    <item android:id="@+id/menu_edit"
        android:title="Edit Item"
        android:icon="@android:drawable/ic_menu_edit"
        appcompat:showAsAction="ifRoom" />
    <item android:id="@+id/menu_settings"
        android:title="Settings"
        android:icon="@android:drawable/ic_menu_preferences"
        appcompat:showAsAction="never" />
</menu>

title和icon属性定义了每个条目该如何显示,旧版本平台会显示这两个值,而新版本中会显示一个或根据位置显示另一个。只有Android 3.0及以后的设备可以识别showAsAction属性,该属性定义了条目是否应该变成Action Bar中的一个动作或者放到溢出菜单中。这个属性最常用的值如下:

  • always : 总是作为一个动作显示其图标。
  • never : 总是显示在溢出菜单中并显示其名称。
  • ifRoom : 如果Action Bar上有空间,就作为动作显示,否则显示在溢出菜单中。

菜单中的第一个条目还定义了android:actionLayout资源,该资源指向在点击此条目时要展开到其中的小部件;此外还定义了额外的显示标志collapseActionView,该标志告诉框架,此条目有可折叠的动作视图以供显示。此代码清单显示了动作视图布局,这是带有两个CheckBox实例的简单布局。

res/layout/view_action.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <CheckBox 
        android:id="@+id/option_first"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="First"/>
    <CheckBox
        android:id="@+id/option_second" 
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Second"/>
</LinearLayout>

以下的代码清单显示了完整的Activity,其中将选项菜单填充到Action Bar中,同时在某个动作项中放置可展开的动作视图。

覆写菜单动作的Activity

public class OptionsActivity extends ActionBarActivity implements
        PopupMenu.OnMenuItemClickListener,
        CompoundButton.OnCheckedChangeListener {

    private MenuItem mOptionsItem;
    private CheckBox mFirstOption, mSecondOption;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //此例中无附加工作
}
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //使用此回调创建菜单并执行任何必要的初始化设置
        getMenuInflater().inflate(R.menu.options, menu);
        
        //查找并初始化动作项
        mOptionsItem = menu.findItem(R.id.menu_add);
        MenuItemCompat.setOnActionExpandListener(mOptionsItem, new MenuItemCompat.OnActionExpandListener() {
            
            @Override
            public boolean onMenuItemActionExpand(MenuItem item) {
                //必须返回true以使项展开
                return true;
            }
            
            @Override
            public boolean onMenuItemActionCollapse(MenuItem item) {
                mFirstOption.setChecked(false);
                mSecondOption.setChecked(false);
                //必须返回true以使项折叠
                return true;
            }
        });
        
        mFirstOption = (CheckBox) MenuItemCompat.getActionView(mOptionsItem).findViewById(R.id.option_first);
        mFirstOption.setOnCheckedChangeListener(this);
        mSecondOption = (CheckBox) MenuItemCompat.getActionView(mOptionsItem).findViewById(R.id.option_second);
        mSecondOption.setOnCheckedChangeListener(this);
        
        return true;
    }
    
    /* 复选框回调方法 */
    
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (mFirstOption.isChecked() && mSecondOption.isChecked()) {
              //隐藏动作视图
            MenuItemCompat.collapseActionView(mOptionsItem);
        }
    }
    
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        //使用此回调执行每次菜单打开时需要调用的设置
        return super.onPrepareOptionsMenu(menu);
    }
    
    //通过PopupMenu点击的回调
    public boolean onMenuItemClick(MenuItem item) {
        menuItemSelected(item);
        return true;        
    }
    
    //通过标准选项菜单点击的回调
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        menuItemSelected(item);
        return true;
    }
    
    //私有辅助方法,让每个回调可以触发相同的动作
    private void menuItemSelected(MenuItem item) {
        //按id获得选择的选项
        switch (item.getItemId()) {
        case R.id.menu_add:
            //执行添加动作
            break;
        case R.id.menu_remove:
            //执行删除动作
            break;
        case R.id.menu_edit:
            //执行编辑动作
            break;
        case R.id.menu_settings:
            //执行设置动作
            break;
        default:
            break;
        }
    }
}

在用户按下设备上的MENU键后(或者Activity在加载时显示了Action Bar),就会调用onCreateOptionsMenu()方法来构建菜单。有一个名为MenuInflater的特殊LayoutInflater对象,可以用来根据XML创建菜单。这里我们使用Activity中已有的getMenuInflater()方法获得MenuInflater实例来创建XML菜单。
如果需要在用户每次打开菜单时传递一些动作,可以在onPrepareOptionsMenu()中完成。这里有一个建议,就是所有变成位于ActionBar中的动作在用户选择它们时将不会触发这个回调方法,但在溢出菜单中的动作还会触发该方法。
用户做了选择后,onOptionsItemSelected()回调方法将会触发同时传入选择的菜单条目。因为我们在XML中为每个条目都定义了唯一的ID,所以可以通过switch语句判断用户的选择项并进行相应的操作。
最后,在onCreateOptionsMenu()中有一些用于可展开动作视图的额外设置。在此获得指向包含动作视图布局的菜单项的引用,并且附加一个onActionExpandListener回调。此外使用回调只是为了在条目折叠时清除动作视图中的已选元素。

要点:
如果提供onActionExpandListener,就需要在onMenuItemActionExpand()内返回true,否则永远不会展开!

可以使用MenuItem中的getActionView()方法获得一个引用,该引用指向在菜单XML中设置的已填充动作布局。在我们的实例中,使用此方法对布局内的每个CheckBox设置选择的侦听器。在动作视图内同时选择这两个条目时,调用collapseActionView()将视图转变回单个动作项的图标。
下图显示了不同版本和配置的设备上这个菜单的样子。依然带有物理按键的设备会在Action Bar上显示提示的动作,但溢出菜单还是通过MENU键触发的。带有软键的设备会挨着Action Bar动作显示一个溢出菜单按钮。
带有物理按键的Android设备

带有软键的Android设备

下图显示了展开的动作视图,单击Action Bar中的Add动作时就会显示该视图。
带有Add动作的Android设备

自定义动作视图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值