日常的开发中,我们需要为RecyclerView添加头尾布局,当我们已经写好了一个adapter,这时候如果要现在添加头尾布局,通常的做法是重写刚写完的adapter,再getItemViewType方法里返回不同的类型,并且其他方法也要改写,这样的话要改的地方太多,所以,我们可以用一个装饰类思路去设计新的adapter,在不改写原来的adapter的情况下,继续为RecyclerView添加头尾布局。在此,引出了类HeaderAndFooterWrapper.
好处:再原来的adapter上加以装饰,姿势更优雅,更解耦。
public class HeaderAndFooterWrapper<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
private static final int BASE_ITEM_TYPE_HEADER = 100000;
private static final int BASE_ITEM_TYPE_FOOTER = 200000;
/**
* SparseArrayCompat(安卓封装自己高效的api)
* 代替HashMap,只不过他们的键(key)的类型是整型Integer或者Long类型
*
* SparseArray<T>与SparseArrayCompat<T>和LongSparseArray<T>
* 这3个类中,前2个基本上是同一类,只不过第二个类有removeAt方法,第三个是Long类型的。
*
* 如果用到了: HashMap<Integer, E> hashMap = new HashMap<Integer, E>();
* 可以替换为:SparseArray<E> sparseArray = new SparseArray<E>();
*/
//HashMap<Intent,View> mHeaderViews = new HashMap<>();
private SparseArrayCompat<View> mHeaderViews = new SparseArrayCompat<>();//头布局的view
private SparseArrayCompat<View> mFootViews = new SparseArrayCompat<>();//尾布局的view
private RecyclerView.Adapter mInnerAdapter;
public HeaderAndFooterWrapper(RecyclerView.Adapter adapter)
{
mInnerAdapter = adapter;
}
/**
* 根据不同的头尾部返回不同的ViewHolder
* 依次接收来自getItemViewType() 传过来的类型,此方法也会执行多次
* 可见的view的类型都依次传进去
* viewType
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
Log.e("viewType", "viewType:== "+viewType );
//View view = mHeaderViews.get(viewType);
if (mHeaderViews.get(viewType) != null)
{
View itemView = mHeaderViews.get(viewType);
ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), itemView);
return holder;
} else if (mFootViews.get(viewType) != null)
{
ViewHolder holder = ViewHolder.createViewHolder(parent.getContext(), mFootViews.get(viewType));
return holder;
}
return mInnerAdapter.onCreateViewHolder(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
if (isHeaderViewPos(position))
{
return;
}
if (isFooterViewPos(position))
{
return;
}
mInnerAdapter.onBindViewHolder(holder, position - getHeadersCount());
}
/**
* getItemViewType 返回值 是你某一种样式 的类型 是什么。。返回值也是 int类型 ,意思是 代表 A类型的 是 数字 1.。。就是这意思
*
* 根据有无头尾部返回不同的int值
*
* position:每一个可见的view的位置(该方法会走多次)
* 该方法的作用:每个view的类型(把这个view的位置给你,你给给我返回一个类型)
*
* 该方法会走多次,一有可见的view,就会依次把它们的位置传进去,position从零开始
*/
@Override
public int getItemViewType(int position)
{
Log.e("getItemViewType", "getItemViewType: ==" + position);
if (isHeaderViewPos(position))
{
//这个值其实就是我们addHeaderView时的key
int i = mHeaderViews.keyAt(position);
Log.e("getItemViewType", "keyAt: =="+i);
//查看第几个位置的键:
return mHeaderViews.keyAt(position);
} else if (isFooterViewPos(position))
{
return mFootViews.keyAt(position - getHeadersCount() - getRealItemCount());
}
//始终返回零
return mInnerAdapter.getItemViewType(position - getHeadersCount());
}
@Override
public int getItemCount()
{
return getHeadersCount() + getFootersCount() + getRealItemCount();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView)
{
WrapperUtils.onAttachedToRecyclerView(mInnerAdapter, recyclerView, new WrapperUtils.SpanSizeCallback() {
@Override
public int getSpanSize(GridLayoutManager layoutManager, GridLayoutManager.SpanSizeLookup oldLookup, int position) {
int viewType = getItemViewType(position);
if (mHeaderViews.get(viewType) != null) {
return layoutManager.getSpanCount();
} else if (mFootViews.get(viewType) != null) {
return layoutManager.getSpanCount();
}
if (oldLookup != null)
return oldLookup.getSpanSize(position);
return 1;
}
});
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder)
{
mInnerAdapter.onViewAttachedToWindow(holder);
int position = holder.getLayoutPosition();
if (isHeaderViewPos(position) || isFooterViewPos(position))
{
WrapperUtils.setFullSpan(holder);
}
}
private boolean isHeaderViewPos(int position)
{
/**
* position 从零开始
* getHeadersCount() 头布局的总数
*
* 这个位置小于头布局的总数就是头布局
*/
return position < getHeadersCount();
}
private boolean isFooterViewPos(int position)
{
return position >= getHeadersCount() + getRealItemCount();
}
//头布局的集合
public void addHeaderView(View view)
{
mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER, view);
Log.e("mHeaderViews", "mHeaderViews.size(): =="+mHeaderViews.size());
}
public void addFootView(View view)
{
mFootViews.put(mFootViews.size() + BASE_ITEM_TYPE_FOOTER, view);
}
//头布局view的个数
public int getHeadersCount()
{
return mHeaderViews.size();
}
//尾布局的个数
public int getFootersCount()
{
return mFootViews.size();
}
//Adapter 子view的个数 不包含头部的个数
private int getRealItemCount()
{
return mInnerAdapter.getItemCount();
}
}
这些就是全部的代码,很简单,慢慢看看就明白了。over。