RecyclerView添加头部和尾部(无侵入Adapter)

市面上也有很多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

你可能感兴趣的:(RecyclerView添加头部和尾部(无侵入Adapter))