带HeaderView和FooterView的自定义RecyclerView.Adapter

-- 实现类似于listView中的addHeaderView方法和addFooterView方法

------##序言今天要给大家介绍的是自定义的RecyclerView.Adapter,名字叫做 BaseHeadFootAdapter,通过这个Adapter你可以像ListView一样在RecyclerView中直接添加HeaderView和FooterView,你只需要写下面几行代码。

 //MyBaseHeadFootAdapter继承自BaseHeadFootAdapter  

adapter=new MyBaseHeadFootAdapter(this,list); 
adapter.addHeaderView(headView); 
adapter.addFooterView(footView);
recyclerView.setAdapter(adapter);

然后你就可以实现这样的效果!

这里写图片描述

使用

如果你只是单纯的想使用,你可以直接点击进入下面的gitHub,你可以看到如何使用它(博客后边其实也有交代),如果你有任何疑问,欢迎关注我的微博同我交流。如果我的项目对你有一丢丢帮助的话,记得star或者follow我哦!

GitHub地址: 自定义HeadFootAdapter

微博:蝎子莱莱的微博

在使用ListView的过程中有两个方法很常用到,那就是ListView中的addHeaderView()和addFooterView(),他们的作用显而易见,那就是在你的listView中添加特殊的两个布局,一个是在顶端,另一个会在底端。如果你没有使用过它们可能会有点好奇,直接把这些布局放在listView上面不就行了吗,为什么非要把它添加到listView里面去呢?
这是因为有这样一种情况我们经常会遇到,下面是京东的一张截图,如果让你去实现这样一个布局你会怎么做呢?

这里写图片描述

你可能会这样做:最外面是一个ScrollView,上面是三张图片那个布局,下面是一个ListView。当然,这样是肯定不行的,你会发现ScrollView和ListView是会滑动冲突的,具体的解决方案你可以看这篇方案

四种方案解决ScrollView嵌套ListView问题

里面提到一种方案和我今天说的很类似,但是不一样,上面说你可以将顶部的布局当成是一种item,因为ListView中的adapter是支持多种type的。但是我个人觉得这种方法并不是很优美,只是一个头部VIew却让你的adapter中代码变得很臃肿,我个人更加倾向于将这个布局放在HeaderView中,你不需要改变adapter中的代码,只需要在Activity中引用添加这个View就好了。
但是RecyclerView的出现是对ListView是一个很大的威胁,RecyclerView上有着太多超越ListView的地方,现在更多是推荐使用RecyclerView,二者的区别这里我们不细讨论,你可以参考下面这篇博客

Android控件RecyclerView和ListView的异同

如果你不是很了解RecyclerView,你可以参考下面这篇博文

RecyclerView:更高级更灵活的ListView

但是RecyclerView也不是完美的,在RecyclerView中很多ListView有的功能它反而没有,比如setOnItemClickListener(),当然这个可以你自己来写,难度并不是很大。还有的就是今天我们要说的addHeaderView()和addFooterView(),所以我自己实现了一个RecyclerView的Adapter,通过这个adapter,你可以像ListView一样 直接使用addHeaderView和addFooterView两个方法。

实现

好了,重点来了,说说代码是如何实现的。其实实现非常简单,聪明的你一定也已经想到了。思路就是,其实在RecyclerView中也是支持Adapter中存在多种type的item的,那么我们可以把HeaderView和FooterView当做两种不同的type,我们要做的事情就是想办法将其封装起来,当在项目中使用时,你根本不会感觉到它们的存在,你要做的只是添加addHeaderView()或者addFooterView()而已。BaseHeadFootAdapter是一个抽象类,你需要继承它并且实现它的几个函数就可以了,这几个函数基本和RecyclerView.Adapter一毛一样(我本来就是做的一点封装)

   /** * 将头部布局返回到用户继承之后的子类中, 
   * * 用户可以这个方法里得到headerVIew,对其进行操作
   * * 比如说headerView中的各种点击事件以及headerView中各种控件的获取 
   * * * @param headerView */ 
protected abstract void onBindHeaderView(View headerView); 
  /** * 将尾部布局返回到用户继承之后的子类中, 
   * * 用户可以这个方法里得到footerVIew,对其进行操作
   * * 比如说headerView中的各种点击事件以及headerView中各种控件的获取
   * * * @param footerView */
 protected abstract void onBindFooterView(View footerView); 
   /** * 获取子类中item的个数 * @return */ protected abstract int getItemNum();
   /** * 子类需继承的方法之一,和onBindViewHolder方法是一样的 
    * * 在这里我进行了封装
    * * * @param holder
    * @param position */
 protected abstract void onBindView(RecyclerView.ViewHolder holder, int position);
    /** * 子类需继承的方法之一,和onCreateViewHolder一样
    * * 这里只是进行了封装
    * * * @param parent
    * @param viewType * @return */ 
protected abstract RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType);

仔细看着几个方法,其实getItemNum()就是RecyclerView.Adapter中的getItemCount(),onBindView(···)就是onBindViewHolder(···),getViewType()就是getItemViewType(),这三个方法也是继承Adapter必须要实现的方法。而另外两个onBindHeaderView(View headerView),onBindFooterView(View footerView)是之前没有的,用户可以在这两个方法中获取自己设置的headerView或者footerView,并且使用它们(比如设置点击事件或者设置view中控件的值)前面提到的我在这个类中做了封装,这里我们拿onCreateViewHolder举例,看下面的代码

 @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
           if(viewType==HEAD_TYPE){ 
        return new HeadFooterViewHolder(headerView); }
   else if(viewType==FOOT_TYPE){
        return new HeadFooterViewHolder(footerView); }
   else //如果不是头布局和尾部局,那么就使用子类中的onCreateHolder方法中指定的ViewHolder 
        return onCreateHolder(parent, viewType); }

其实你就会很清楚,如果是HeaderView我就创建HeaderView的viewHolder,如果是普通的item就使用用户实现的onCreateHolder(···)来创建,因为这个方法是个虚函数,是用户实现的。其他的两个方法也是同样的道理分装起来的,我就不再赘述,感兴趣的话你可以查看我的源码。

使用

使用起来的话也非常简单,你只需要将我的BaseHeadFootAdapter类拷贝的你项目中,并且继承它实现它的几个方法即可。和你使用原生的RecyclerView.Adapter是完全一样的,你的item也可以有多种type,但是要记得type值不要是-100和-101(已经被HeaderView和FooterView占用了)。最后你只需在你自己的Adapter中调用方法即可。

adapter.addHeaderView(headView); 
adapter.addFooterView(footView);

这样你就可以在你的Adapter(继承自BaseHeadFootAdapter)中对header和FooterView进行操作,下面以HeaderView为例

@Override protected void onBindHeaderView(View headerView) { 
    headerView.setOnClickListener(new View.OnClickListener() { 
          @Override public void onClick(View view) { 
             Toast.makeText(context,"head was clicked",Toast.LENGTH_SHORT).show(); 
           }  
       });
      }

其实,只要你掌握了RecyclerView的基本用法很快就可以使用这个自定义的Adapter,我gitHub中那个project是一个使用了这个Adapter的例子,你可以参考一下,其中MyBaseHeadFootAdapter是继承自BaseHeadFootAdapter的Adapter类,MyViewHolder是item的viewHolder(和RecyclerView的标准写法是一样的)。最后,还是将github和我的微博贴出来,欢迎大家和我交流学习。谢谢!

GitHub地址: 自定义HeadFootAdapter
微博:蝎子莱莱的微博

[1]: http://weibo.com/xiezilailai [2]: http://bbs.anzhuo.cn/thread-982250-1-1.html [3]: http://www.tuicool.com/articles/aeeaQ3J [4]: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0710/1631.html

推荐阅读更多精彩内容