android记事本开发笔记2-记事列表的多选操作

   一般来说,在安卓应用中listview的多选操作都是和ActionMode结合起来的。ActionMode可以理解为actionbar的另一种形式,同样可以在菜单中添加动作项,同样可以通过setCustomView自定义标题栏,并且当启动ActionMode之后,它所占据的位置是和actionbar重叠的。使用ActionMode的好处是可以在同一个activity中完成多选操作,且切换成新的视图时,切换的整个过程非常自然,并且ActionMode有自己的回调方法。其实ActionMode仅仅是一种视觉上的实现,多选的功能和ActionMode本身一点关系都没有。actionbar和ActionMode我理解为在一个activity中的两种模式,不同的模式下做不同的操作。

   ActionMode最典型的例子是android4.0上邮件应用和mms应用。当你查看一个邮件列表或者查看短信列表的时候,长按一个item,将会进入ActionMode模式。
下面我用图片展示一下actionbar和ActionMode模式。

图1:正常情况下记事本的列表界面是这样的:图2:当我选择多选进入ActionMode之后:

 关于actionmode最基本的用法请看这篇文章:安卓中的上下文操作模式ActionMode

 我也是看了这篇文章之后,仿照着写出来的,但是直接这样写编程的时候会出现一些问题 。当我点击一个记事的时候,右图右上角的数字应该相应变化,但是在activity里面实现actionmode接口的却是一个内部类:

private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {
    // Called when the action mode is created; startActionMode() was called
    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        // Inflate a menu resource providing context menu items
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.context_menu, menu);
        return true;
    }
    // Called each time the action mode is shown. Always called after onCreateActionMode, but
    // may be called multiple times if the mode is invalidated.
    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false; // Return false if nothing is done
    }
    // Called when the user selects a contextual menu item
    @Override
    public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_share:
                shareCurrentItem();
                mode.finish(); // Action picked, so close the CAB
                return true;
            default:
                return false;
        }
    }
    // Called when the user exits the action mode
    @Override
    public void onDestroyActionMode(ActionMode mode) {
        mActionMode = null;
    }
};

在activity中没法直接操作里面的视图。因此我换一种写法,让activity实现这个接口,那么actionmode的视图就能在activity中随意的操作了。

extends Activity implements OnClickListener,ActionMode.Callback

然后在启动actionmode的时候,这个回调对象就是activity自己:

} else if (view == mMenuAction) {当点击多选按钮//
    if (mActionMode != null) {
        return ;
    }
    // Start the CAB using the ActionMode.Callback defined above
    mActionMode = startActionMode(this);
   ......
}

Activit实现`ActionMode`最重要的回调方法是onCreateActionMode,在这个方法中,我将标题栏设置成自定义的视图,视图的布局在layout目录下的xml文件中。

xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/custom_title_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/title"
        android:maxLines="1"
        android:singleLine="true"
        android:layout_gravity="center_vertical"
        android:layout_centerVertical="true"
        android:textAppearance="?android:attr/textAppearanceMediumInverse"
        android:layout_weight="1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/selected_count"
        android:maxLines="1"
        android:singleLine="true"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:layout_gravity="center_vertical"
        android:paddingRight="10dip"
        android:textColor="#FFFFFF"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

然后在activity

@Override
 public boolean onCreateActionMode(ActionMode mode, Menu menu) {
     MenuInflater inflater = getMenuInflater();
     inflater.inflate(R.menu.note_list_action_options, menu);
     mSelectAndDelete= menu.findItem(R.id.delete);        
     if (mMultiSelectActionBarView == null) {
         mMultiSelectActionBarView = LayoutInflater.from(PenNoteActivity.this)
             .inflate(R.layout.list_multi_select_action, null);
         mSelectedConvCount =
             (TextView)mMultiSelectActionBarView.findViewById(R.id.selected_count);
     }
     mode.setCustomView(mMultiSelectActionBarView);
     ((TextView)mMultiSelectActionBarView.findViewById(R.id.title))
         .setText(R.string.multi_select);
     mSelectedConvCount.setText("0");
     return true;
 }

其中`mode.setCustomView(mMultiSelectActionBarView);`一行就是将标题栏设置成自定义布局。

按照上面的代码执行之后,我们就得到了图2最上面的效果,但是你应该注意到图2和图1的不同之处还有下面部分。下面是动作项,具体的定义是在menu里面,如果要在actionmode中采用某个menu,需要在onCreateActionMode中这样做:

MenuInflater inflater = getMenuInflater();

inflater.inflate(R.menu.note_list_action_options, menu);

`menu.note_list_action_options就是menu下的一个xml文件:`

<?xml version="1.0" encoding="UTF-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/delete"
        android:title="@string/delete"
        android:icon="@drawable/delete"
        android:showAsAction="ifRoom"
        />
</menu>

如图2所示,我们只定义了一个删除菜单。响应这个菜单动作的代码实现在 ActionMode.Callback接口的onActionItemClicked方法里。

@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
    switch (item.getItemId()) {
        case R.id.delete:
           // shareCurrentItem();
            mode.finish(); // Action picked, so close the CAB
            return true;
        default:
            return false;
    }
}

关于多选就讲这些,其实这个笔记的重点在于如何正确的运用actionmode,我这里的方法是在activity中直接实现ActionMode.Callback接口,这样代码会好些很多。