这是一个老生常谈的问题,现在网上搜搜已经到处是答案,但是RecyclerView刚出来的时候可是让很多人苦恼过,甚至有人想把ListView中的HeaderView和FooterView硬搬过来,而且还要考虑列表中真实数据错位问题,很麻烦。
其实是完全没有必要的,列表加headerView是小事,中间穿插多个不一样的view才是重点,尤其像头条新闻这类应用,列表中会穿插各种形状各异的栏目,还有比较典型的是聊天应用(微信),聊天列表中有各种UI呈现形式(图片,文字,视频,音乐,表情,地图等等)。
其实Android已经提供给我们办法了,而且是一个非常解耦的办法:通过自定义的viewType来区别对待创建viewHolder和给viewHolder绑定数据。
/**
* 所有viewHolder数据类的基类
*/
public class ViewTypeData {
public interface ViewType {
int HEAD = 10000;
int FOOT = 10001;
int DEFAULT = 0;
}
public int viewType = ViewType.DEFAULT;
public ViewTypeData (int viewType){
this.viewType = viewType;
}
}
public class ViewTypeDataA extends ViewTypeData {
public static final int VIEW_TYPE = 1;
public String name;
public int age;
public int height;
public ViewTypeDataA(){
super(VIEW_TYPE);
}
}
public class ViewTypeDataB extends ViewTypeData {
public static final int VIEW_TYPE = 2;
public String pic;
public int title;
public int subTitle;
public ViewTypeDataB(){
super(VIEW_TYPE);
}
}
public class ViewTypeDataC extends ViewTypeData {
public static final int VIEW_TYPE = 3;
public String city;
public int district;
public int address;
public ViewTypeDataC(){
super(VIEW_TYPE);
}
}
这里我们约定所有要呈现在RecyclerView中的数据类(json类)在定义时都继承ViewTypeData并在其构造方法里赋值告知对应的viewType值。
public class RecyclerViewAdapter extends RecyclerView.Adapter{
private List<ViewTypeData> mDataList = new ArrayList<>();
public void setData(List<ViewTypeData> dataList){
mDataList = dataList;
notifyDataSetChanged();
}
@Override
public RecyclerView.ViewHolder onCreateiewHolder(@NonNull ViewGroup parent, int viewType) {
switch(viewType){
if (viewType == ViewTypeDataA.VIEW_TYPE) {
return new ViewHolderA(inflater.inflate(R.layout.view_type_a, parent, false));
} else if (viewType == ViewTypeDataB.VIEW_TYPE) {
return new ViewHolderB(inflater.inflate(R.layout.view_type_b, parent, false));
} else if (viewType == ViewTypeDataC.VIEW_TYPE) {
return new ViewHolderC(inflater.inflate(R.layout.view_type_c, parent, false));
}
// 有多少种item的呈现形式就有多少种viewType
}
}
@Override
protected void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
ViewTypeData data = mDataList.get(position);
if (holder instanceof ViewHolderA){
ViewHolderA viewHolder = (ViewHolderA)holder;
viewHolder.setData((ViewTypeAData)data);
} else if (viewType instanceof ViewHolderB){
ViewHolderB viewHolder = (ViewHolderB)holder;
viewHolder.setData((ViewTypeBData)data);
} else if (viewType instanceof ViewHolderC){
ViewHolderC viewHolder = (ViewHolderC)holder;
viewHolder.setData((ViewTypeCData)data);
}
// 有多少种item的呈现形式就有多少种viewHolder赋值
}
@Override
public int getItemCount() {
return mDataList.size();
}
}
// 模拟不同形式的列表数据插入
List<ViewTypeData> dataList = new ArrayList<>();
dataList.addAll(viewTypeDataAList);
dataList.addAll(viewTypeDataBList);
dataList.addAll(viewTypeDataCList);
recycleViewAdapter.setData(dataList);
由上可见列表中不同的item展示是根据viewType一一判断生成的,但为什么说这是一种解耦的思路呢?
在具体项目中,列表中的数据来源可能来自多个接口,也有可能是特定的逻辑本地生成然后插入的,最重要的列表中item显示的顺序如何保证。从解耦角度考虑,这跟传入到RecyclerViewAdapter里的dataList数据有直接关系,这里的dataList某种意义上讲就是一个先进先出的队列,数据在dataList是什么顺序在列表中呈现就是什么顺序。因此工作的重心是如何组织dataList里的数据以及顺序,而不是在adapter里牵扯各种业务逻辑,毕竟adapter内部也有它烦人的工作要做,如:UI的渲染,事件的监听等,只希望它们之间的工作没有强关联。
我想现在要在RecyclerView里加个headerView不麻烦了吧。
网友评论