优雅的为RecyclerView添加头尾布局HeaderAndFooterWrapper

日常的开发中,我们需要为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。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值