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'
複製代碼
相關文章
相關標籤/搜索