recyclerview-selection简化RecyclerView复选及状态持久化

题记

在查看RecyclerView的官方文档的时候发现了这个recyclerview-selection库,通过测试感受功能挺好的,省去了本身须要编写大量多选功能的代码,官方文档的guide又不是太清晰,这篇文章仅仅做为简单的记录。html

参考:java

  1. 如何将多个选择添加到Android RecyclerView(Kotlin)
  2. RecyclerView-Selection(Kotlin)
  3. github示例代码(Java)
  4. Create a List with RecyclerView——Google
  5. androidx.recyclerview.selection——Google

说明

根据官方文档的描述,这个库就是用来处理RecyclerView的Item的选择问题,而且能够在设备配置改变的时候保存已选择的数据,从新建立页面的时候再次加载,省去了咱们本身对这部分的操做;同时经过观察者模式提供了item点击监听、长按订阅功能。 android

使用

  1. 选择一个key的类型。用来构建ItemKeyProvider;可选择的类型目前只有三种: String:基于字符串的稳定标识符可使用String; Long:当RecyclerView的long stable Id已经在使用时,使用long,可是会有一些限制,在运行时访问一个稳定的id会被限定(不过目前没有发现有什么限定,测试中直接使用了list的索引); Parcelable:任何Parcelable均可以用做selection的key,若是view中的内容与稳定的content:// uri相关联,就是用uri做为key的类型;(这个尚未试验)
public class StringItemKeyProvider extends ItemKeyProvider<String> {

    private List<String> items;

    public StringItemKeyProvider(int scope, List<String> items) {
        super(scope);
        this.items = items;
    }

    @Nullable
    @Override
    public String getKey(int position) {
        return items.get(position);
    }

    @Override
    public int getPosition(@NonNull String key) {
        return items.indexOf(key);
    }
}

复制代码
  1. 实现ItemDetailsLookup接口,该接口能够接受RecyclerView的Item上发生的MotionEvent事件,咱们须要实现其ItemDetails getItemDetails(@NonNull MotionEvent e)方法,经过ReyclerView的findChildView(int,int)方法来判断具体touch的是哪个Item,强转成咱们的ViewHolder类型,调用咱们RecyclerView.ViewHolder中的方法来返回一个ItemDetails实例,返回实例的方法是咱们本身添加的,ViewHolder中并无该抽象方法
public class StringItemDetailsLookup extends ItemDetailsLookup {

    private final RecyclerView mRecyclerView;

    StringItemDetailsLookup(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
    }

    @Nullable
    @Override
    public ItemDetails getItemDetails(@NonNull MotionEvent e) {
        View view = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
        if (view != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
            if (holder instanceof StringItemRecyclerViewAdapter.ItemViewHolder) {
                return ((StringItemRecyclerViewAdapter.ItemViewHolder) holder).getItemDetails();
            }
        }
        return null;
    }
}
复制代码

如下是返回ItemDetails实例的方法,其中注释的语句是经过继承ItemDetails的子类来建立的。git

ItemDetailsLookup.ItemDetails getItemDetails() {
//                return new StringItemDetail(getAdapterPosition(),datas.get(getAdapterPosition()));
                return new ItemDetailsLookup.ItemDetails() {
                    @Override
                    public int getPosition() {
                        return getAdapterPosition();
                    }

                    @Nullable
                    @Override
                    public Object getSelectionKey() {
                        return datas.get(getAdapterPosition());
                    }
                };
            }
复制代码
public class StringItemDetails extends ItemDetailsLookup.ItemDetails {

    private int position;
    private String item;

    public StringItemDetails(int position, String item) {
        this.position = position;
        this.item = item;
    }

    @Override
    public int getPosition() {
        return position;
    }

    @Nullable
    @Override
    public Object getSelectionKey() {
        return item;
    }
}
复制代码

如今咱们准备好了StringItemDetailsLookupStringItemKeyProvider两个类,可是准备好了又怎么用呢?github

  1. 建立SelectionTracker实例,在Activity的OnCreate中加入以下代码(注意是在一个参数的OnCreate中,Android5.0以上两个参数的方法只有在Manifast文件为Activity设置了android:persistableMode属性才会调用,一样onSaveInstanceStateonRestoreInstanceState也是如此,没注意参数个数致使我浪费 了大半个小时,哭),建立基本的实例,其余的查看源码便可:
mAdapter = new StringItemRecyclerViewAdapter(ITEMS);
        mRecyclerView.setAdapter(mAdapter);
        mSelectionTracker = new SelectionTracker.Builder<>(
                "string-items-selection",
                mRecyclerView,
                new StringItemKeyProvider(1, ITEMS),
                new StringItemDetailsLookup(mRecyclerView),
                StorageStrategy.createStringStorage())
                //设置可选择的item,这里设置为均可选
                .withSelectionPredicate(SelectionPredicates.<String>createSelectAnything())
                .build();
        mAdapter.setSelectionTracker(mSelectionTracker);
复制代码

注意上边setSelectionTracker方法,这个方法是咱们在自定义的RecyclerView.Adapter中添加的,目的是将咱们建立的SelectionTracker注入到咱们的Adpter。bash

public void setSelectionTracker(SelectionTracker mSelectionTracker) {
    this.mSelectionTracker = mSelectionTracker;
 }
复制代码

前边说了,咱们在Adapter中添加了getItemDetails方法,如今咱们的基本工做已经完成,程序能正常运行了,可是咱们还看不到多选的效果,由于tracker并不能为咱们提供选中高亮功能,高亮功能按咱们喜欢的方式实现便可,判断是否选中的代码以下(在Adapter的onBindViewHolder方法中):ide

if (mTracker.isSelected(datas.get(i))) {
                viewHolder.tvInfo.setBackgroundColor(Color.parseColor("#80deea"));
            } else {
                viewHolder.tvInfo.setBackgroundColor(Color.WHITE);
            }
复制代码
  1. 前边的代码已经足以咱们完成RecyclerView多选功能,可是当屏幕配置改变,好比旋转屏幕时,咱们已选中的item的选中状态就会消失,因此咱们须要将咱们的选中状态进行持久化操做,tracker为提供了相应的API方便咱们持久化,将数据持久化操做与Activity的生命周期事件进行绑定。在Activity的onSaveInstanceStateonRestoreInstanceState中分别调用tracker的onSaveInstanceStateonRestoreInstanceState方法便可,以下:
@Override
 protected void onRestoreInstanceState(Bundle savedInstanceState) {

    super.onRestoreInstanceState(savedInstanceState);
    if (savedInstanceState != null) {
        mSelectionTracker.onRestoreInstanceState(savedInstanceState);
    }
 }
 @Override
 protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    mSelectionTracker.onSaveInstanceState(outState);
 }
复制代码

后续

咱们能够为tracker添加订阅事件或者item单击事件,这样选择状态改变或者item被点击是咱们能够添加本身的逻辑,后续多选操做及多选信息咱们均可以经过tracker的事件或者方法得到,具体请看参考3的代码或者查看官网SelectionTracker的说明。测试

最后,必须第一步的操做,Android studio 3.4居然没法直接搜索recyclerview添加其依赖,搜索结果是androidx版本的,会有冲突,recyclerview-selection却是能够直接搜索依赖到项目中。ui

implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:recyclerview-selection:28.0.0'
复制代码
相关文章
相关标签/搜索