Android 5.X新特性之为RecyclerView添加HeaderView和FooterView

上一节咱们讲到了 Android 5.X新特性之RecyclerView基本解析及无限复用 相信你们也应该熟悉了RecyclerView的基本使用,这一节咱们来学习下,为RecyclerView添加HeaderView和FooterView。html

针对RecyclerView的头部和底部,官方并无给咱们提供像listView同样能够直接经过addHeaderView()/addFooterView()的方法,因此只能靠咱们本身去实现了,那怎么实现呢?你们都知道RecyclerView已经为咱们封装好了Adapter和ViewHolder,在Adapter中咱们须要重写onCreateViewHolder(ViewGroup parent, int viewType)这个方法方便咱们把ItemView布局文件或是自定义View传递到ViewHolder中,从而达到ItemView的重复使用和回收等。而咱们今天要讲的添加头部和底部和该方法有密不可分的关系。python

你们仔细观察onCreateViewHolder(ViewGroup parent, int viewType)这个方法,在它的参数中,含有一个viewType,它就表明了每个子列表中的ItemView的类型,而该类型咱们又能够经过Adapter中封装好的getItemViewType()方法来定义。所以,咱们能够根据这两个方法来完成咱们今天的学习。微信

首先,咱们也须要在BaseRecyclerAdapter中添加一个addHeaderView的方法,用于接受Activity中传递过来的HeaderView,而且把HeaderView添加到第0个ItemView中。ide

private View mHeaderView;
    public void addHeaderView(View headerView){
        mHeaderView = headerView;
        notifyItemInserted(0);
    }

而后,咱们在咱们自定义的BaseRecyclerAdapter中重写getItemViewType()方法,而且定义两个静态变量来区分咱们的viewType的类型,以下:布局

public final static int TYPE_HEADER = 0;
    public final static int TYPE_BODY = 1;
    @Override
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }

ok,如今咱们能够针对getItemViewType()方法来为咱们的ItemView设置viewType类型了。咱们知道,getItemViewType()默认返回的是0这个类型,因此咱们重载该方法,在没有mHeaderView时,咱们让它返回TYPE_BODY这个类型,而当有mHeaderView,因为把它添加到第0个ItemView中了,因此咱们能够根据position等于0的时候让它返回TYPE_HEADER这个类型。定义好的类型将会在onCreateViewHolder()中使用到。学习

因此咱们的getItemViewType方法能够这样设计:this

@Override
    public int getItemViewType(int position) {
        if(mHeaderView == null)
            return TYPE_BODY;
        if(position == 0) {
            return TYPE_HEADER;
        }
        return TYPE_BODY;
    }

到这里你们已经很明确的知道了每一个ItemView的viewType类型了,那么咱们就能够在onCreateViewHolder()方法中根据ItemView的viewType来作出不一样的判断了,以下:设计

@Override
    public BaseViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType == TYPE_HEADER && mHeaderView != null){
            return new BaseViewHolderHelper(mHeaderView);
        }
        View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
        return new BaseViewHolderHelper(view);
    }

代码一目了然,就是根据viewType判断是否为TYPE_HEADER,若是是,则添加不一样的布局或View,不然,加载正常的布局,其余的不变。code

而后,咱们就能够在onBindViewHolder(BaseViewHolderHelper holder, int position)方法中根据当前的position位置来绑定咱们要显示数据了。htm

@Override
    public void onBindViewHolder(BaseViewHolderHelper holder, int position) {
        if(getItemViewType(position) == TYPE_HEADER){
            return;
        }else{
            if(mHeaderView != null){
                position-- ;
            }
            holder.itemView.setTag(position);
            holder.itemView.setOnClickListener(this);
            holder.itemView.setOnLongClickListener(this);
            T itemData = mDatas.get(position);
            displayContents(holder,itemData);
        }
    }

代码解释:若是当前position位置的类型是TYPE_HEADER,也就是说用来显示mHeaderView的,这里咱们就直接返回mHeaderView的布局,不作事件处理了;若是不是,而且RecyclerView是有带mHeaderView头部的,那么因为它占去第0个itemView,因此咱们的position是从第一个开始计算的,因此咱们必须获得当前真实position位置,并经过position位置来获取当前的真实数据,若是不带mHeaderView头部,则可直接根据position获取显示数据,其余的逻辑不变。

还有注意的是当mHeaderView不为空时,咱们的数据量大小也有必定的变化,请看:

@Override
    public int getItemCount() {
        return mHeaderView != null ? mDatas.size() + 1 : mDatas.size();
    }

ok,在RecycerActivity的onCreate方法中添加一下两句:

View headerView = LayoutInflater.from(this).inflate(R.layout.item_view1, null);
mBaseRecyclerAdapter.addHeaderView(headerView);

来看看运行结果吧

这里写图片描述

ok,已经完成了mHeaderView 的添加。可是有个小问题,当你把RecyclerView的布局设置为GridLayoutManager时,如:mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));就会出现这种状况:

这里写图片描述

这种状况也很好解决,在GridLayoutManager中咱们能够在SpanSizeLookup中从新设置显示的列数。

@Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if(manager instanceof GridLayoutManager){
            final GridLayoutManager gridLayoutManager = ((GridLayoutManager) manager);
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    //是HeaderView则占全部列,不然只占本身列
                    return getItemViewType(position) == TYPE_HEADER ? gridLayoutManager.getSpanCount() : 1;
                }
            });
        }
    }

最主要的就是在getSpanSize方法中根据咱们的须要从新设置就ok了。看看吧
这里写图片描述

好了,mHeaderView 已基本搞定,如今来看看怎么添加FooterView了,其实原理是同样的,也是根据getItemViewType()返回的ViewType类型来加载不一样的布局了。

首先咱们须要定义一个内部类FooterViewHolder继承咱们的BaseViewHolderHelper,它主要是用来绑定FooterView布局文件:

private class FooterViewHolder extends BaseViewHolderHelper{
        private TextView footView;
        public FooterViewHolder(View itemView) {
            super(itemView);
            footView = (TextView) itemView.findViewById(R.id.tv_addFooter);
        }
    }

而后在getItemViewType中获取到最后的ItemView的位置并返回TYPE_FOOTER类型:

@Override
    private View mFooterView;
    public final static int TYPE_FOOTER = 2;
    ......
    
    public int getItemViewType(int position) {
        if(position + 1 == getItemCount()){
            return TYPE_FOOTER;
        }
        if(mHeaderView == null)
            return TYPE_BODY;
        if(position == 0) {
            return TYPE_HEADER;
        }
        return TYPE_BODY;
    }

另外在getItemCount()方法中咱们由于添加个一个FooterView因此须要在原来的基础上再加 1 ;

@Override
    public int getItemCount() {
        return mHeaderView != null ? mDatas.size() + 2 : mDatas.size() + 1;
    }

再次在onCreateViewHolder方法中根据类型加载不一样的布局文件:

@Override
    public BaseViewHolderHelper onCreateViewHolder(ViewGroup parent, int viewType) {
        ...
        
        if(viewType == TYPE_FOOTER){
            mFooterView = LayoutInflater.from(mContext).inflate(R.layout.custom_footerview, parent,false);
            return new FooterViewHolder(mFooterView);
        }
        View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutResId, parent, false);
        return new BaseViewHolderHelper(view);
    }

最后在onBindViewHolder方法中来展现咱们的数据吧

@Override
    public void onBindViewHolder(BaseViewHolderHelper holder, int position) {
        if(getItemViewType(position) == TYPE_HEADER){
            return;
        }else if(getItemViewType(position) == TYPE_FOOTER){
            FooterViewHolder footViewHolder=(FooterViewHolder)holder;
            footViewHolder.footView.setText("上拉加载更多...");
        } else{
            ...
        }
    }

ok,完成,来看看结果吧

这里写图片描述

总结下,在给RecyclerView添加HeaderView和FooterView时,只要利用好getItemViewType这个方法,返回相对应的ViewType,而且在onCreateViewHolder方法中根据ViewType类型加载不一样的布局就彻底但是实现咱们的需求了。提及来就是这么简单。好了,今天就讲到这里吧,祝你们学习愉快。

更多资讯请关注微信平台,有博客更新会及时通知。爱学习爱技术。

这里写图片描述

相关文章
相关标签/搜索