让你的 RecyclerView 支持多选

下图演示的是 RecyclerView 图片多选,未使用第三方库。如何让 RecyclerView 支持多选,可以从几个方面思考,我们可以按下面的构思来设计这个小功能。

  • 视图:Item 的长相应该有个可以让用户点击选择、可以显示选择状态的控件,所以 Item 布局可以有一个 CheckBox
  • 数据模型:Item 的数据模型需要能够表达、记录这个对象的 Select 状态,所以 Item 的数据模型应该有一个 boolean is_selected 的属性。
  • 控制器:当用户的多选发生变化时,需要能够获取多选数据,反映出一个多选功能的状况。

1. 布局

下面的代码是 RecyclerView Item 的布局。2 个 View 放在 RelativeLayout 里叠起来便成了开头 Demo 图呈现的那个样子。

  • ImageView(id itemview_imageview),显示图片。
  • CheckBox(id itemview_checkbox),支持用户点击选择,这个是半透的。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="1dp">

<ImageView
android:id="@+id/itemview_imageview"
android:contentDescription="@null"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop" />

<CheckBox
android:id="@+id/itemview_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#80ffffff"
android:maxLines="1"
android:ellipsize="end" />
</RelativeLayout>

2. 数据模型

Item 的数据模型如下代码所示。

  • is_selected 如前面提到的,用来记录这个 Item 的选择状态。
  • bitmap 是图片,例子图片是从 raw 加载的所以用了 Bitmap 类型。
  • title 图片的 title,可以显示在 CheckBox 上。
class ItemData {
String title;
Bitmap bitmap;
boolean is_selected;

ItemData(String title, Bitmap bitmap, boolean selected) {
this.title = title;
this.bitmap = bitmap;
this.is_selected = selected;
}
}

3. 适配器

适配器的代码我列出了如下几个部分

  • ItemView 作为 Item 的 ViewHolder,为了避免低效的在 onBindViewHolder 里做 findViewById,这里缓存了 2 个 View 的引用。
  • onBindViewHolder 当一个 Item 显示的时候,根据 ItemData(如上面提到的 bitmap、is_selected、title)来设置这个 Item 的显示,如果之前有选择状态就会被设为 Checked。
  • onCheckedChanged 当一个 Item 显示的时候,也注册了的 onCheckedChanged 事件侦听,当该 Item 的选择状态改变则会存入对应(position)的 ItemData。
  • getSelected 这个方法返回一个 selection 列表,作为演示我在选择改变时打印输出了选择状况。
static class ItemView extends RecyclerView.ViewHolder {
ImageView mImageView;
CheckBox mCheckBox;

ItemView(View itemView) {
super(itemView);

mImageView = itemView.findViewById(R.id.itemview_imageview);
mCheckBox = itemView.findViewById(R.id.itemview_checkbox);
}
}

@Override
public void onBindViewHolder(ItemView holder, int position) {
final ItemData item = mItems.get(position);

holder.mImageView.getLayoutParams().height = ROW_HEIGHT;
holder.mImageView.setImageBitmap(item.bitmap);

holder.mCheckBox.setText(item.title);
holder.mCheckBox.setChecked(item.is_selected);
holder.mCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
item.is_selected = b;

StringBuilder sb = new StringBuilder();
for (ItemData item : getSelected()) {
sb.append(item.title).append(", ");
}

android.util.Log.i("selected:", sb.toString());
}
});
}

private ArrayList<ItemData> getSelected() {
ArrayList<ItemData> selects = new ArrayList<>();
for (ItemData item : mItems) {
if (item.is_selected) {
selects.add(item);
}
}

return selects;
}

4. 运行

本文的思路是给每个 Item 对象添加选择数据,每当有选择改变时查找所有被选择的 Item 并打印出来。当有选择变化时输出信息如下,即实现了多选的功能。

logcat

最近更新 2017-08-18