RecycleView是Goolgle在高级版本中提出的一个替代ListView、GridView的控件,特点就是自带了ViewHolder进行了性能优化,而且高度解耦。但是在RecycleView并没有ListView的addHeaderView和addFooterView方法,在开发中可能会带来不便,所以接下来就是封装一个自定义RecycleView来实现这两个功能。
一、ListView源码分析
首先,既然ListView中有该方法,可以参考来看一下
public void addHeaderView(View v, Object data, boolean isSelectable) {
...
if (!(mAdapter instanceof HeaderViewListAdapter)) {
wrapHeaderListAdapterInternal();
}
...
}
看一下这个wrapHeaderListAdapterInternal()是啥?
protected void wrapHeaderListAdapterInternal() {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
protected HeaderViewListAdapter wrapHeaderListAdapterInternal(
ArrayList<ListView.FixedViewInfo> headerViewInfos,
ArrayList<ListView.FixedViewInfo> footerViewInfos,
ListAdapter adapter) {
return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter);
}
这儿就返回了一个HeaderViewListAdapter?
接着分析HeaderViewListAdapter源码,原来这只是一个自定义的adapter,把原先的adapter传进去,然后加工一下(中间代理模式)返回
Okay,接着看一下ListView的setAdapter方法,果不其然
public void setAdapter(ListAdapter adapter) {
...
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos,mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
...
从上面来看,我们可以通过一个中间件,即中间代理模式,将RecycleView的普通adapter转换一下,就可以实现需求了
So,new 一个WrapRecyclerView继承RecyclerView,实现addHeaderView、addFooterView、setAdapter,代码如下
public class WrapRecyclerView extends RecyclerView{
private ArrayList<View> mHeaderViewInfos = new ArrayList<>();
private ArrayList<View> mFooterViewInfos = new ArrayList<>();
private Adapter mAdapter;
public WrapRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void addHeaderView(View v) {
mHeaderViewInfos.add(v);
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
}
}
public void addFooterView(View v) {
mFooterViewInfos.add(v);
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);
}
}
}
@Override
public void setAdapter(Adapter adapter) {
if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {
mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
super.setAdapter(mAdapter);
}
}
接着就是文章重点了,自定义一个HeaderViewRecyclerAdapter中间件
public class HeaderViewRecyclerAdapter extends Adapter {
private Adapter mAdapter;
private ArrayList<View> mHeaderViewInfos;
private ArrayList<View> mFooterViewInfos;
public HeaderViewRecyclerAdapter(ArrayList<View> headerViewInfos,
ArrayList<View> footerViewInfos, Adapter adapter) {
mAdapter = adapter;
if (headerViewInfos == null) {
mHeaderViewInfos = new ArrayList<>();
} else {
mHeaderViewInfos = headerViewInfos;
}
if (footerViewInfos == null) {
mFooterViewInfos = new ArrayList<>();
} else {
mFooterViewInfos = footerViewInfos;
}
}
@Override
public int getItemCount() {
if (mAdapter != null) {
return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();
} else {
return getFootersCount() + getHeadersCount();
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
int numHeaders = getHeadersCount();
if (position < numHeaders) {
return ;
}
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
mAdapter.onBindViewHolder(holder, adjPosition);
}
}
}
@Override
public int getItemViewType(int position) {
int numHeaders = getHeadersCount();
if (position < numHeaders) {
return RecyclerView.INVALID_TYPE;
}
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
return mAdapter.getItemViewType(adjPosition);
}
}
return RecyclerView.INVALID_TYPE-1;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType==RecyclerView.INVALID_TYPE){
return new HeaderViewHolder(mHeaderViewInfos.get(0));
}else if(viewType==RecyclerView.INVALID_TYPE-1){//footer
return new HeaderViewHolder(mFooterViewInfos.get(0));
}
return mAdapter.onCreateViewHolder(parent, viewType);
}
public int getHeadersCount() {
return mHeaderViewInfos.size();
}
public int getFootersCount() {
return mFooterViewInfos.size();
}
private static class HeaderViewHolder extends ViewHolder{
public HeaderViewHolder(View view) {
super(view);
}
}
Okay,接下来的实现UI代码很简单,就不继续下去了。从这个自定义头部可以看出,RecycleView具有的强大的扩展性,在高度解耦的同时提供了自定义功能,不得不感慨一下设计的思路是真的supreme。事实上你也可以通过其他的方式也可以实现,只需在你自己的Adapter中的getItemCount()中增加头部和底部的数目,然后在getItemViewType()中根据所需位置返回特定值,再在onCreateViewHolder()和onBindViewHolder()和加载视图和绑定数据就ok啦!