1. 程式人生 > >封裝RecyclerView Adapter 實現可新增多個header和footer,可設定loadingView,低耦合的多種佈局。

封裝RecyclerView Adapter 實現可新增多個header和footer,可設定loadingView,低耦合的多種佈局。

多種佈局的recyclerview的普通寫法是重寫RecyclerView.Adapter的getItemViewType返回不同position上的type,在onCreateViewHolder(ViewGroup parent,int viewType)里根據不同的type建立不同的viewholder,之後在onBindViewHolder(RecyclerView.ViewHolder holder, int position)里根據不同的viewholder進行資料繫結。但是這種寫法具有高度耦合性,每新增一種佈局都要在adapter的三個方法做修改。
改進方法
首先封裝一個BaseViewHolder:

public abstract class BaseViewHolder<T> extends RecyclerView.ViewHolder {

    View mItemView;
    //快取View
    SparseArray<View> mViews;

    public BaseViewHolder(View itemView) {
        super(itemView);
        mItemView = itemView;
        mViews = new SparseArray<>();
    }

    public
View getView(int resId) { View view = mViews.get(resId); if (view == null) { view = mItemView.findViewById(resId); mViews.put(resId, view); } return view; } public void setVisibility(int resId, boolean visible) { View view = getView(resId); if
(view != null) { view.setVisibility(visible ? View.VISIBLE : View.GONE); } } public abstract void bindData(T data); }

使用SparseArray快取View,避免每次都呼叫findViewById。
然後建立一個介面,裡面包含根據不同bean返回不同type型別的方法,和建立ViewHolder的方法:

public interface TypeFactory {
    BaseViewHolder createViewHolder(int type, View itemView);
    int type(ChannelEntity channelEntity);
    int type(EntityTwo entityTwo);
}

然後建立TypeFactory的實現類實現上述方法,其中type方法返回對應的佈局id,因為id不可重複,這樣就可以利用id值作為不同佈局型別的type值:

public class ItemTypeFactory implements TypeFactory{
    @Override
    public BaseViewHolder createViewHolder(int type, View itemView) {
        switch (type){
            case R.layout.item_my:
                return new ViewHolderOne(itemView);
            case R.layout.item_other:
                return new ViewHolderTwo(itemView);
        }
        return null;
    }

    @Override
    public int type(ChannelEntity channelEntity) {
        return R.layout.item_my;
    }

    @Override
    public int type(EntityTwo entityTwo) {
        return R.layout.item_other;
    }
}

接下來建立實體bean類的抽象基類,包含一個抽象方法

public abstract class BaseModel {
    public abstract int type(TypeFactory typeFactory) ;
}

建立不同的實體類

public class ChannelEntity extends BaseModel {
    int id;
    String name;
    String letter;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLetter() {
        return letter;
    }

    public void setLetter(String letter) {
        this.letter = letter;
    }

    @Override
    public int type(TypeFactory typeFactory) {
        return typeFactory.type(this);
    }
}

最後是BaseRecyclerAdapter,裡面包含一個ItemTypeFactory例項,然後在getItemViewType(int position)返回mData.get(getRealPosition(position)).type(itemTypeFactory);將不同佈局檔案id作為type返回:

@Override
    public int getItemViewType(int position) {

                return mData.get(getRealPosition(position)).type(itemTypeFactory);
    }

在onCreateViewHolder(ViewGroup parent, int viewType)里根據getItemViewType方法裡返回的不同的佈局id來建立對應的ViewHolder

 @Override
    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                return itemTypeFactory.createViewHolder(viewType, view);
        }

    }

最後在onBindViewHolder方法裡呼叫baseviewholder的bindData方法繫結資料。
此外我還在BaseRecyclerAdapter裡實現了新增頭尾佈局及列表底部的loading佈局的方法,以及在更新資料時利用DiffUtil對新舊資料集比較,防止呼叫notifyDataSetChanged來更新整個recyclerView。具體請看我的github上的程式碼:
戳我下載程式碼