Android RecyclerView 是Android5.0推出来的,导入support-v7包即可使用。
RecyclerView是一款功能强大的控件,优势体现在:
但是用起来也有一些麻烦之处:
有BaeQuickAdapter之前,想要使用RecyclerView需要做哪些工作?
我们要自定义Adapter继承RecyclerView.Adapter,需要做的工作包括:
构造函数要传入一个View参数,这个参数就是RecyclerView子项的最外层布局,通过findViewById()方法来获取布局中的控件,把他们设置成ViewHolder的成员变量,方便对其进行数据绑定。
onCreateViewHolder方法
参数:ViewGroup parent, int viewType
用途:用于创建ViewHolder实例。通过inflate加载layout布局文件创建view,传递给ViewHolder持有。可以根据viewType的不同,返回不同的ViewHolder。
返回:自定义的ViewHolder类型的viewholder
onBindViewHolder方法
参数:viewholder,position
用途:用于对RecyclerView子项的数据进行赋值,会在每个子项滚动到屏幕内的时候执行。按照position位置取出子项的数据实例,把数据实例中的数据内容绑定到参数viewholder中,设置显示内容、点击等。
getItemCount
用途:返回控件中要显示的数据个数
一般还需要自己定义一个list,持有数据列表。可以在构造函数中,把数据列表传入进来。
当按照position取数据的时候都需要从这个列表中读取。
与ListView不同,RecyclerView没有提供类似setOnItemClickListener()这样的注册监听器方法,而是需要我们自己给子项具体的View去注册点击事件,相比于ListView来说,实现起来要复杂一些。
这里要提一下,为什么在点击事件上RecyclerView做的反而不如ListView了?
其实,ListView在点击事件上的处理并不人性化,tsetOnItemClickListener()方法注册的是子项的点击事件,但是如果想实现自向内具体就一个控件的点击,就比较麻烦了。所以RecyclerView就直接摒弃了子项点击事件。
为了RecyclerView注册点击时间。可以在onCreateViewHolder中,为自定义ViewHolder的控件成员对象设置监听,因为都是View类型,直接使用setOnClickListener方法即可。
BaseQuickAdapter比起RecyclerView.Adapter用起来要方便很多,主要体现在以下几个方面。
比起RecyclerView.Adapter只有一个泛型VH extends RecyclerView.ViewHolder,BaseQuickAdapter另外增加一个:
public abstract class BaseQuickAdapter<T, K extends BaseViewHolder> extends RecyclerView.Adapter<K>
其中BaseViewHolder继承RecyclerView.ViewHolder,K需要继承BaseViewHolder;T为数据集中的数据类型,类型内部持有了T类型的列表List
。
继承RecyclerView.Adapter需要自己在重写的onCreateViewHolder方法中通过inflate创建view。
这里我们根据RecyclerView中展示数据的布局样式是单一的还是多种的分为两类:
而BRVAH提供了两种adapter,BaseQuickAdapter和BaseMultiItemQuickAdapter。
作为单一样式的Adapter,BaseQuickAdapter提供了很方便的设置布局方法——构造函数直接接收layoutId作为参数,不需要重复去写创建view的过程。
虽然说是单一样式,但是其实BaseQuickAdapter还可以设置头部和脚部,只要中间是单一类型就可以用。
作为BaseQuickAdapter的子类,只需要实现一个abstract方法——convert方法
参数:viewholder helper,T item
内容:与onBindViewHolder类似,进行数据绑定。只是这里的helper是BaseViewHolder,作者为BaseViewHolder封装了很多好用的方法,下文具体讲。
BaseQuickAdapter继承RecyclerView.Adapter,需要实现的那3个abstract方法,BaseQuickAdapter替我们实现了。
上文我们提到,onCreateViewHolder方法的需要创建view,传递给自定义的ViewHolder类型的对象去持有。参数中的viewType用来区分类型,返回不同的ViewHolder对象。
源码如下:
@Override
public K onCreateViewHolder(ViewGroup parent, int viewType) {
K baseViewHolder = null;
this.mContext = parent.getContext();
this.mLayoutInflater = LayoutInflater.from(mContext);
switch (viewType) {
case LOADING_VIEW:
baseViewHolder = getLoadingView(parent);
break;
case HEADER_VIEW:
baseViewHolder = createBaseViewHolder(mHeaderLayout);
break;
case EMPTY_VIEW:
baseViewHolder = createBaseViewHolder(mEmptyLayout);
break;
case FOOTER_VIEW:
baseViewHolder = createBaseViewHolder(mFooterLayout);
break;
default:
baseViewHolder = onCreateDefViewHolder(parent, viewType);
bindViewClickListener(baseViewHolder);
}
baseViewHolder.setAdapter(this);
return baseViewHolder;
}
switch (viewType),根据不同的viewType创建ViewHolder,viewType包括头部、尾部、loading、空状态和普通的数据。
***创建ViewHolder的方法还涉及泛型的知识。
onBindViewHolder
对于头部尾部等ViewType的数据,都不需要绑定,对于普通类型的数据,调用我们实现的convert方法即可,需要注意的是,这里传递给convert的position其实是RecyclerView.Adapter中的position去掉头部之后的。
getItemCount
考虑是否是空页面的情况,如果是空页面返回头部尾部等的个数;如果不是空页面,返回mdata的长度+头部尾部个数。
使用BaseViewHolder继承自RecyclerView.ViewHolder,它提供了封装好的方法,供开发者方便地进行数据绑定。如果没有特殊需求,只是要进行一些控件的属性设置,不需要重新写一个新的子类去继承BaseViewHolder了。
对于不同的控件,BaseViewHolder直接提供了很多设置属性的方法。
例如对于TextView空间,可以直接调用helper.setText()对其设置text内容,传入参数为view的id和字符内容。源码:
public BaseViewHolder setText(@IdRes int viewId, CharSequence value) {
TextView view = getView(viewId);
view.setText(value);
return this;
}
其他的如imageView,CheckBox等也提供了setImageResoure/Gone/Checked等方法。
通过上一小节给出的源码可以看见,setXXX方法返回的还是BaseViewHolder,所以可以链式调用,使用方便,可读性好。
BaseViewHolder对设置控件点击事件的方法做了统一封装:addOnClickListener和addOnLongClickListener。
这两个方法的传入参数都是view的id,然后调用View的setOnClickListener和setOnLongClickListener方法给他们设置点击的回调函数,这里的回调函数是BaseQuickAdapter中的mOnItemChildClickListener和mOnItemChildLongClickListener两个函数。
private OnItemChildClickListener mOnItemChildClickListener;
private OnItemChildLongClickListener mOnItemChildLongClickListener;
所以在使用的时候需要调用BaseQuickAdapter的两个set方法:
/**
* Register a callback to be invoked when an itemchild in View has
* been clicked
*
* @param listener The callback that will run
*/
public void setOnItemChildClickListener(OnItemChildClickListener listener) {
mOnItemChildClickListener = listener;
}
/**
* Register a callback to be invoked when an item in this RecyclerView has
* been long clicked and held
*
* @param listener The callback that will run
*/
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
}
虽然也支持直接setOnClickListener给某一个view,但是作者更加推荐的是这种方法。
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private OnItemChildClickListener mOnItemChildClickListener;
private OnItemChildLongClickListener mOnItemChildLongClickListener;