现在基本大家都推荐RecyclerView,很少有人使用ListView了,包括我自己也是,已经很久没用ListView了,所以关于ListView的万能adapter就不写了。
每次写项目的时候,每次遇到RecyclerView都要重新写一个Adapter,一大堆东西重复写,麻烦死了,实在是忍不住了,以前懒,总是懒得去搞快捷的adapter,现在项目里面好多个RecyclerView,马丹,写adapter写吐,所以麻溜麻溜的来写个万能adapter了,这种东西网上很多,原理差不多都是重写ViewHolder和Adapter,主要是使用泛型实现。废话不多说,撸代码吧。
注意:我的万能adapter中集成了下拉刷新、上拉加载更多、另增header的功能,需要与我后面将写到的万能下拉刷新、上拉加载更多的RecyclerView搭配使用,如果你不需要下拉刷新和上拉加载更多可以无视其中相关的代码。
首先,我们知道我们对adapter中控件获取都是通过ViewHolder来的,所以我们首先要自定义ViewHolder,来完成各个控件的获取和初始化。正常情况下,我们是这样用的:
class HistoryGoodsHolder extends RecyclerView.ViewHolder {
ImageView img;
TextView name, summary, amount, price;
public HistoryGoodsHolder(View itemView) {
super(itemView);
img = (ImageView) itemView.findViewById(R.id.item_history_rcv_goodsImg);
name = (TextView) itemView.findViewById(R.id.item_history_rcv_goodsName);
summary = (TextView) itemView.findViewById(R.id.item_history_rcv_goodsSummary);
amount = (TextView) itemView.findViewById(R.id.item_history_rcv_goodsAmount);
price = (TextView) itemView.findViewById(R.id.item_history_rcv_goodsPrice);
}
}
现在我们需要实现的是万能的adapter,所以holder必须实现可定制化,而不是这种固定死的,每个RecyclerView的item布局不一样就重新写个holder,这样就没有意义了,所以我们写的万能Holder中不能存在真实的控件id,因为一旦id固定,那么肯定得重复写holder,毕竟id不一样,holder就不一样了,所以我们可以通过一种方式,那就是findById方法里面的id不写死,而是用参数的方式传进去,这样可以写一个通用的Holer,不同的recyclerview可以传不同的id进去就行了。ViewHolder最终形态:
public class XJJBaseRvHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mViews; //view的集合
private View mConvertView; //item的布局
private Context mContext; //上下文
public XJJBaseRvHolder(Context context, View itemView) {
super(itemView);
mContext = context;
mConvertView = itemView;
mViews = new SparseArray<View>();
}
//获取item的布局
public View getItemView(){
return mConvertView;
}
//初始化控件,通过传进去id来初始化,使用泛型实现传递任何类型
public <T extends View> T getView(int viewId)
{
View view = mViews.get(viewId);
if (view == null)
{
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
//快捷设置TextView的文本
public XJJBaseRvHolder setText(int viewId, String text)
{
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
//快捷设置ImageView的图片
public XJJBaseRvHolder setSrc(int viewId, int resId)
{
ImageView view = getView(viewId);
view.setImageResource(resId);
return this;
}
//设置控件的点击事件
public XJJBaseRvHolder setOnClickListener(int viewId, View.OnClickListener listener)
{
View view = getView(viewId);
view.setOnClickListener(listener);
return this;
}
//设置item的点击事件
public XJJBaseRvHolder setItemOnClickListener(View.OnClickListener listener){
mConvertView.setOnClickListener(listener);
return this;
}
ViewHolder搞定,接下来是adapter,ViewHolder是在adapter里面被引用的,如果我们在adapter里面实例化holder后传入id来初始化控件,肯定不行,因为如果在adapter里面传入id,那么adapter使用了真实的id,那么id不一样adapter又得不一样,还得重复写了,所以我们不能在adapter里面传入id来初始化item的控件,那么怎么实现呢?用接口来实现,具体如下:
先写接口把Holder传递出去,然后初始化adapter的时候实现改接口。
public interface ItemDataListener<T> {
//接口
void setItemData(XJJBaseRvHolder holder, T t);
}
public void setItemDataListener(ItemDataListener listener) {
itemDataListener = listener;
}
然后我们数据填充的时候需要先初始化控件的,所以我在onBindViewHolder里面调用接口