RecycleView添加头部和底部

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啦!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容