开篇先放代码:戳我下载代码
多种布局的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上的代码:
戳我下载代码