市面上也有很多recyclerview添加头部和尾部的各种封装demo,但是最后都是业务adapter要继承被封装的BaseAdapter,今天就给大家写一篇无侵入Adapter,无缝对接项目里已经写好的adapter
private static final int HEADERS_START = Integer.MIN_VALUE;
private static final int FOOTERS_START = Integer.MIN_VALUE + 10;
private static final int ITEMS_START = Integer.MIN_VALUE + 20;
private static final int ADAPTER_MAX_TYPES = 100;
private RecyclerView.Adapter mWrappedAdapter;
private List mHeaderViews, mFooterViews;
public HeaderViewGridRecyclerAdapter(RecyclerView.Adapter adapter) {
mHeaderViews = new ArrayList<>();
mFooterViews = new ArrayList<>();
mItemTypesOffset = new HashMap<>();
setWrappedAdapter(adapter);
}
public void setAdapter(RecyclerView.Adapter adapter) {
if (mWrappedAdapter != null && mWrappedAdapter.getItemCount() > 0) {
notifyItemRangeRemoved(getHeaderCount(), mWrappedAdapter.getItemCount());
}
setWrappedAdapter(adapter);
notifyItemRangeInserted(getHeaderCount(), mWrappedAdapter.getItemCount());
}
@Override
public int getItemViewType(int position) {
int hCount = getHeaderCount();
if (position < hCount) {
return HEADERS_START + position;
} else {
int itemCount = mWrappedAdapter.getItemCount();
if (position < hCount + itemCount) {
return getAdapterTypeOffset() + mWrappedAdapter.getItemViewType(position - hCount);
} else {
return FOOTERS_START + position - hCount - itemCount;
}
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
if (viewType < HEADERS_START + getHeaderCount()) {
return new StaticViewHolder(mHeaderViews.get(viewType - HEADERS_START));
} else if (viewType < FOOTERS_START + getFooterCount()) {
return new StaticViewHolder(mFooterViews.get(viewType - FOOTERS_START));
} else {
return mWrappedAdapter.onCreateViewHolder(viewGroup, viewType - getAdapterTypeOffset());
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
int hCount = getHeaderCount();
if (position >= hCount && position < hCount + mWrappedAdapter.getItemCount()) {
mWrappedAdapter.onBindViewHolder(viewHolder, position - hCount);
}
}
1.首页列HeaderViewGridRecyclerAdapter ,recyclerview需要的adapter,来处理头部和尾部的位置
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int spanSize = 1; //每个griditem 占1份 一行有3个网格item 每个spansize为1 一个item占满则需要返回3
int hCount = getHeaderCount();
if (position < hCount) {
return gridLayoutManager.getSpanCount();
}
int itemCount = mWrappedAdapter.getItemCount();
if (position >= hCount + itemCount) {
return gridLayoutManager.getSpanCount();
}
return spanSize;
}
});
}
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder viewHolder) {
super.onViewAttachedToWindow(viewHolder);
if (viewHolder.itemView.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams) {
int viewType = viewHolder.getItemViewType();
if (viewType < HEADERS_START + getHeaderCount()) {
// 获取cardview的布局属性,记住这里要是布局的最外层的控件的布局属性,如果是里层的会报cast错误
StaggeredGridLayoutManager.LayoutParams clp = (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
// 最最关键一步,设置当前view占满列数,这样就可以占据两列实现头部了
if (clp != null)
clp.setFullSpan(true);
} else if (viewType < FOOTERS_START + getFooterCount()) {
// 获取cardview的布局属性,记住这里要是布局的最外层的控件的布局属性,如果是里层的会报cast错误
StaggeredGridLayoutManager.LayoutParams clp1 = (StaggeredGridLayoutManager.LayoutParams) viewHolder.itemView.getLayoutParams();
// 最最关键一步,设置当前view占满列数,这样就可以占据两列实现头部了
clp1.setFullSpan(true);
}
}
}
2.在adapter里重写onAttachedToRecyclerView,实现GridLayoutManager有头部时让头部item 占1份
重写onViewAttachedToWindow,实现StaggeredGridLayoutManager有头部时让头部item 占1份
private void setWrappedAdapter(RecyclerView.Adapter adapter) {
if (mWrappedAdapter != null) mWrappedAdapter.unregisterAdapterDataObserver(mDataObserver);
mWrappedAdapter = adapter;
Class adapterClass = mWrappedAdapter.getClass();
if (!mItemTypesOffset.containsKey(adapterClass)) putAdapterTypeOffset(adapterClass);
mWrappedAdapter.registerAdapterDataObserver(mDataObserver);
}
private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
super.onItemRangeChanged(positionStart, itemCount);
notifyItemRangeChanged(positionStart + getHeaderCount(), itemCount);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
notifyItemRangeInserted(positionStart + getHeaderCount(), itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
super.onItemRangeRemoved(positionStart, itemCount);
notifyItemRangeRemoved(positionStart + getHeaderCount(), itemCount);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
super.onItemRangeMoved(fromPosition, toPosition, itemCount);
int hCount = getHeaderCount();
// TODO: No notifyItemRangeMoved method?
notifyItemRangeChanged(fromPosition + hCount, toPosition + hCount + itemCount);
}
};
3.mWrappedAdapter为业务adapter,去重新监听registerAdapterDataObserver,当业务adapter.notifyDataSetChanged()时,可以回调到这里来交给主adapter处理事件
public void addHeaderView(View view) {
mHeaderViews.add(view);
}
public void addFooterView(View view) {
mFooterViews.add(view);
}
4.这是添加头部和尾部,只需传入View即可
public class SpaceItemDecoration extends RecyclerView.ItemDecoration {
private void setNGridLayoutSpaceItemDecoration2(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if (headItemCount != 0 && parent.getChildAdapterPosition(view)
5.给StaggeredGridLayoutManager瀑布流添加item的space时,头部不加间隔,item用lp.getSpanIndex() % 2 == 0判断添加间隔
大致就这些,可能写的不是很清晰,但是看项目源码就一清二楚了
最后献上GitHub地址:https://github.com/veneno94/RecyclerViewDemo