学会自己给RecyclerView添加Header、Footer和加载更多回调

3,134 阅读27分钟

        说来也惭愧,RecyclerView都出来了多么久了,但我还在listview中畅游,继续这样是不行的,是时候展现新的技术了。对于习惯了listview的我来说,刚开始觉得RecyclerView不就和listview一样吗,而且还没有添加header和footer的方法,真是简直了,当得知了一些很复杂酷炫的布局都是用RecyclerView实现的时候,我承认我眼拙了,放着这么优秀的控件不用,真是悔之晚矣呀。所以现在就都把listview改成了RecyclerView,并为之添加了添加头和添加尾的方法和加载更多的回调方法,至于下拉刷新就取用别人写好的轮子吧。还是老规矩,先上图,看看劳动成果在开干:

listview类型的线性列表:


gridview类型的多列列表:


大家是不是觉得这两种效果应该能满足大部分需求了吧,其实不然,这里用了设计模式中的——装饰者模式,对你们自己的RecyclerViewAdapter没有任何入侵,只是在外层包裹了一层功能而已,你们的RecyclerViewAdapter的所以功能都完全保留了的,完全非入侵,想怎么玩就怎么玩。

首先讲一讲“装饰者模式”是怎样的:

        比如有个类A,A中有a和b两个方法,然后新的需求需要给A添加一个c方法,此时我们想到的都是集成A,然后再在里面添加c方法,这是完全可以的,但是随后又需要添加d方法,我们就又需要集成A,然后添加d方法,但是需求是在彼变的,可能会加很多,然后我们就写很多集成类?NO~,我们不能再这么干, 不然会疯掉的。解决这个问题就需要用到“装饰者模式”了,它是把原来的类进行一次同类型(原来的类集成谁,这个也继承谁)的封装,并且原来的类完全不用改变,达到了零入侵。比如:我们现在已经有了A类了,然后需要添加一个c方法,我们可以设计一个类B集成A,然后里面添加一个A类型的变量,然后把c方法也添加后,构造参数里面传入A类型的变量,后面就可以使用B来代替A了,并且里面添加了c方法,A里面的功能照旧,这样就完成了对A的修饰,伪代码如下:

  1. //A 类  
  2. class A  
  3. {  
  4.     void a();  
  5.     void b();  
  6. }  
  7. //B类  
  8. class B extends A  
  9. {  
  10.     A a;  
  11.     B(A a)  
  12.     {  
  13.         this.a = a;  
  14.     }  
  15.     void a()  
  16.     {  
  17.         a.a();  
  18.     }  
  19.     void c();  
  20. }  
  21.   
  22. //使用  
  23. A a = new A();  
  24. B b = new B(a);  
  25. b.c();  
    //A 类
    class A
    {
        void a();
        void b();
    }
    //B类
    class B extends A
    {
        A a;
        B(A a)
        {
            this.a = a;
        }
        void a()
        {
            a.a();
        }
        void c();
    }
    
    //使用
    A a = new A();
    B b = new B(a);
    b.c();

我理解的装饰者模式就是这样的,有什么不足之处还请多多包涵。

接下来开始我们的封装吧:

        先来算法:因为RecyclerView很灵活,里面所有的一切对它来说都是一个item,所以我们添加的header和footer也是item,只是这两个item布局不一样并且一个在列表头和列表尾而已,这大概也就是没有默认提供header和fooer的原因了吧。然后我们要做的就是给现有的adapter添加这两个item,根据装饰者模式我们也需要写一个adapter类集成Recy.Adapter类, 并实现默认的onCreateViewHolder、onBindViewHolder和getItemCount三个方法,然后还需要实现getItemViewType这个方法来为第一个返回header的type值,和最后一个footer的type值,这样就可以在onCreateViewHolder方法中根据type来返回不同的viewholder了(headerholder、footerholder、normalholder),其中返回normalholder就是我们传入的adapter.onCreateViewHolder就可以了,其他方法也是类似的,只有不是header或者footer类型的就直接adapter.方法返回就是了。这样就完成了封装。

一、首先用RecyclerView把数据展示出来

(1):导入RecyclerView的库,根据自己的SDK版本来添加

  1. compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'  
compile 'com.android.support:recyclerview-v7:26.0.0-alpha1'
(2):布局文件
  1. <?xml version="1.0" encoding= "utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent">  
  5.   
  6.     <android.support.v7.widget.RecyclerView  
  7.         android:id="@+id/recyclerview"  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent"  
  10.         />  
  11.   
  12. </RelativeLayout>  
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</RelativeLayout>
(3):集成RecyclerView.Adapter类的MyAdapter,并实现默认的onCreateViewHolder、onBindViewHolder和getItemCount三个方法
  1. package com.ywl5320.recyclerveiwdemo;  
  2.   
  3. import android.content.Context;  
  4. import android.support.v7.widget.RecyclerView;  
  5. import android.view.LayoutInflater;  
  6. import android.view.View;  
  7. import android.view.ViewGroup;  
  8. import android.widget.TextView;  
  9.   
  10. import java.util.List;  
  11.   
  12. /** 
  13.  * Created by ywl on 2017-7-23. 
  14.  */  
  15.   
  16. public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{  
  17.   
  18.     private Context context;  
  19.     private List<String> datas;  
  20.   
  21.     public MyAdapter(Context context, List<String> datas) {  
  22.         this.context = context;  
  23.         this.datas = datas;  
  24.     }  
  25.   
  26.     @Override  
  27.     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  28.         View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false);  
  29.         MyHolder holder = new MyHolder(v);  
  30.         return holder;  
  31.     }  
  32.   
  33.     @Override  
  34.     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {  
  35.         ((MyHolder)holder).textView.setText(datas.get(position));  
  36.     }  
  37.   
  38.     @Override  
  39.     public int getItemCount() {  
  40.         return datas.size();  
  41.     }  
  42.   
  43.     public class MyHolder extends RecyclerView.ViewHolder  
  44.     {  
  45.         private TextView textView;  
  46.         public MyHolder(View itemView) {  
  47.             super(itemView);  
  48.             textView = (TextView) itemView.findViewById(R.id.tv_title);  
  49.         }  
  50.     }  
  51. }  
package com.ywl5320.recyclerveiwdemo;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

/**
 * Created by ywl on 2017-7-23.
 */

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    private Context context;
    private List<String> datas;

    public MyAdapter(Context context, List<String> datas) {
        this.context = context;
        this.datas = datas;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false);
        MyHolder holder = new MyHolder(v);
        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ((MyHolder)holder).textView.setText(datas.get(position));
    }

    @Override
    public int getItemCount() {
        return datas.size();
    }

    public class MyHolder extends RecyclerView.ViewHolder
    {
        private TextView textView;
        public MyHolder(View itemView) {
            super(itemView);
            textView = (TextView) itemView.findViewById(R.id.tv_title);
        }
    }
}
因为RecyclerView是强制使用ViewHolder的,并且都是RecyclerView.ViewHolder的子类,所以这里创建了一个MyHolder的类,里面主要负责初始化我们的item的布局。

(4):调用

  1. setContentView(R.layout.activity_main);  
  2.         recyclerView = (RecyclerView) findViewById(R.id.recyclerview);  
  3.         datas = new ArrayList<>();  
  4.         for(int i = 0; i <  60; i++)  
  5.         {  
  6.             datas.add(i + "");  
  7.         }  
  8.         myAdapter = new MyAdapter(this, datas);  
  9.         LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);  
  10.         linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);  
  11.         recyclerView.setLayoutManager(linearLayoutManager);  
  12.         recyclerView.setAdapter(myAdapter);  
setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        datas = new ArrayList<>();
        for(int i = 0; i < 60; i++)
        {
            datas.add(i + "");
        }
        myAdapter = new MyAdapter(this, datas);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(myAdapter);

这就是使用RecyclerView最基本的方法了,这个是没有header和footer的。 二、创建我们的封装类对原来的Adapter进行封装,注意事项和解释都写在代码注释上面比较清晰,我们需要知道的是当我们的adapter传入进来后是怎么运作的

getItemViewType->onCreateViewHolder->onBindViewHolder,然后我们就需要在相应的方法中根据是否有header或者footer进行相应的操作,没有的就直接返回传入的adapter的相应的方法就可以了

  1. package com.ywl5320.recyclerveiwdemo;  
  2.   
  3. import android.support.v7.widget.GridLayoutManager;  
  4. import android.support.v7.widget.RecyclerView;  
  5. import android.view.View;  
  6. import android.view.ViewGroup;  
  7.   
  8. /** 
  9.  * Created by ywl on 2017-7-23. 
  10.  */  
  11.   
  12. public class WapHeaderAndFooterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  
  13.   
  14.     private int headtype = 0x11111;  
  15.     private int normaltype = 0x11112;  
  16.     private int foottype = 0x11113;  
  17.     private View headerView;  
  18.     private View footerView;  
  19.     private RecyclerView.Adapter badapter;//目标adapter  
  20.     private OnLoadMoreListener onloadMoreListener;  
  21.   
  22.   
  23.     public WapHeaderAndFooterAdapter(RecyclerView.Adapter badapter) {  
  24.         this.badapter = badapter;  
  25.     }  
  26.   
  27.     public void addHeader(View header)  
  28.     {  
  29.         headerView = header;  
  30.     }  
  31.   
  32.     public void addFooter(View footer)  
  33.     {  
  34.         footerView = footer;  
  35.     }  
  36.   
  37.     //实现加载更多接口  
  38.     public void setOnloadMoreListener(final OnLoadMoreListener onloadMoreListener, RecyclerView recyclerView) {  
  39.         this.onloadMoreListener = onloadMoreListener;  
  40.         if(recyclerView != null && onloadMoreListener !=  null)  
  41.         {  
  42.             recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {  
  43.                 @Override  
  44.                 public void onScrollStateChanged(RecyclerView recyclerView,  int newState) {  
  45.                     super.onScrollStateChanged(recyclerView, newState);  
  46.                 }  
  47.   
  48.                 @Override  
  49.                 public void onScrolled(RecyclerView recyclerView,  int dx, int dy) {  
  50.                     super.onScrolled(recyclerView, dx, dy);  
  51.                     if(isSlideToBottom(recyclerView))  
  52.                     {  
  53.                         if(onloadMoreListener !=  null)  
  54.                         {  
  55.                             onloadMoreListener.onLoadMore();  
  56.                         }  
  57.                     }  
  58.                 }  
  59.             });  
  60.         }  
  61.     }  
  62.   
  63.     /** 
  64.      * 根据头部尾部返回相应的type,这里if else没有简写,方便看逻辑 
  65.      * @param position 
  66.      * @return 
  67.      */  
  68.     @Override  
  69.     public int getItemViewType(int position) {  
  70.   
  71.         if(headerView != null && footerView !=  null)//同时加了头部和尾部  
  72.         {  
  73.             if(position == 0)//当position为0时,展示header  
  74.             {  
  75.                 return headtype;  
  76.             }  
  77.             else if(position == getItemCount() -  1)//当position为最后一个时,展示footer  
  78.             {  
  79.                 return foottype;  
  80.             }  
  81.             else//其他时候就展示原来adapter的  
  82.             {  
  83.                 return normaltype;  
  84.             }  
  85.         }  
  86.         else if(headerView != null) { //只有头部  
  87.             if (position == 0)  
  88.                 return headtype;  
  89.             return normaltype;  
  90.         }  
  91.         else if(footerView != null) //只有尾部  
  92.         {  
  93.             if(position == getItemCount() - 1)  
  94.             {  
  95.                 return foottype;  
  96.             }  
  97.             else  
  98.             {  
  99.                 return normaltype;  
  100.             }  
  101.         }  
  102.         else {  
  103.             return normaltype;  
  104.         }  
  105.     }  
  106.   
  107.     /** 
  108.      * 这里就根据getItemViewType返回的值来返回相应的ViewHolder 
  109.      * 头部和尾部的ViewHolder只是一个集成RecyclerView.ViewHolder的简单默认类,里面并没有任何处理。 
  110.      * 这样就完成了类型的返回了(需注意为什么这样做) 
  111.      * @param parent 
  112.      * @param viewType 
  113.      * @return 
  114.      */  
  115.     @Override  
  116.     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  117.         if(viewType == headtype)//返回头部的ViewHolder  
  118.             return new HeaderViewHolder(headerView);  
  119.         else if(viewType == foottype)//返回尾部的ViewHolder  
  120.             return new FoogerViewHolder(footerView); //其他就直接返回传入的adapter的ViewHolder  
  121.         return badapter.onCreateViewHolder(parent, viewType);  
  122.     }  
  123.   
  124.     /** 
  125.      * 绑定ViewHolder,当时header或footer时,直接返回,因为不用绑定, 
  126.      * 当是传入的adapter时,就直接调用adapter.onBindViewHolder就行了 
  127.      * @param holder 
  128.      * @param position 
  129.      */  
  130.     @Override  
  131.     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {  
  132.   
  133.         if(headerView != null && footerView !=  null)//有头部和尾部  
  134.         {  
  135.             if(position == 0)//头部直接返回,无需绑定  
  136.             {  
  137.                 return;  
  138.             }  
  139.             else if(position == getItemCount() - 1)//尾部直接返回,也无需绑定  
  140.             {  
  141.                 return;  
  142.             }  
  143.             else  
  144.             {  
  145.                 badapter.onBindViewHolder(holder, position - 1);//其他就调用adapter的绑定方法  
  146.             }  
  147.         }  
  148.         else if(headerView != null)  
  149.         {  
  150.             if(position == 0)  
  151.             {  
  152.                 return;  
  153.             }  
  154.             else  
  155.             {  
  156.                 badapter.onBindViewHolder(holder, position - 1);  
  157.             }  
  158.         }  
  159.         else if(footerView != null)  
  160.         {  
  161.             if(position == getItemCount() - 1)  
  162.             {  
  163.                 return;  
  164.             }  
  165.             else  
  166.             {  
  167.                 badapter.onBindViewHolder(holder, position);  
  168.             }  
  169.         }  
  170.         else  
  171.         {  
  172.             badapter.onBindViewHolder(holder, position);  
  173.         }  
  174.     }  
  175.   
  176.     /** 
  177.      * 返回item的数量, 
  178.      * @return 
  179.      */  
  180.     @Override  
  181.     public int getItemCount() {  
  182.   
  183.         if(headerView != null && footerView !=  null)//有头部和尾部,就多了2  
  184.         {  
  185.             return badapter.getItemCount() + 2;  
  186.         }  
  187.         else if(headerView != null) //只有头部多了1  
  188.         {  
  189.             return badapter.getItemCount() + 1;  
  190.         }  
  191.         else if(footerView != null) //只有尾部也多了1  
  192.         {  
  193.             return badapter.getItemCount() + 1;  
  194.         }  
  195.         return badapter.getItemCount();//其他就是默认的值, 不多也不少  
  196.     }  
  197.   
  198.     /** 
  199.      * 头部的ViewHolder 
  200.      */  
  201.     private class HeaderViewHolder extends RecyclerView.ViewHolder  
  202.     {  
  203.         public HeaderViewHolder(View itemView) {  
  204.             super(itemView);  
  205.         }  
  206.     }  
  207.   
  208.     /** 
  209.      * 尾部的ViewHolder 
  210.      */  
  211.     private class FoogerViewHolder extends RecyclerView.ViewHolder  
  212.     {  
  213.         public FoogerViewHolder(View itemView) {  
  214.             super(itemView);  
  215.         }  
  216.     }  
  217.   
  218.     /** 
  219.      * 处理当时Gridview类型的效果时,也把头部和尾部设置成一整行(这就是RecyclerView的其中一个优秀之处,列表的每行可以不同数量的列) 
  220.      * @param recyclerView 
  221.      */  
  222.     @Override  
  223.     public void onAttachedToRecyclerView(RecyclerView recyclerView) {  
  224.         final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();  
  225.         if(layoutManager instanceof GridLayoutManager)  
  226.         {  
  227.             /** 
  228.              * getSpanSize的返回值的意思是:position位置的item的宽度占几列 
  229.              * 比如总的是4列,然后头部全部显示的话就应该占4列,此时就返回4 
  230.              * 其他的只占一列,所以就返回1,剩下的三列就由后面的item来依次填充。 
  231.              */  
  232.             ((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {  
  233.                 @Override  
  234.                 public int getSpanSize( int position) {  
  235.                     if(headerView != null && footerView !=  null)  
  236.                     {  
  237.                         if(position ==  0)  
  238.                         {  
  239.                             return ((GridLayoutManager) layoutManager).getSpanCount();  
  240.                         }  
  241.                         else if(position == getItemCount() -  1) {  
  242.                             return ((GridLayoutManager) layoutManager).getSpanCount();  
  243.                         }  
  244.                         else  
  245.                         {  
  246.                             return  1;  
  247.                         }  
  248.                     }  
  249.                     else if(headerView !=  null) {  
  250.                         if (position ==  0) {  
  251.                             return ((GridLayoutManager) layoutManager).getSpanCount();  
  252.                         }  
  253.                         return 1;  
  254.                     }  
  255.                     else if(footerView !=  null)  
  256.                     {  
  257.                         if(position == getItemCount() -  1)  
  258.                         {  
  259.                             return ((GridLayoutManager) layoutManager).getSpanCount();  
  260.                         }  
  261.                         return 1;  
  262.                     }  
  263.                     return 1;  
  264.                 }  
  265.             });  
  266.         }  
  267.     }  
  268.   
  269.     /** 
  270.      * 判断是否到底部了 
  271.      * @param recyclerView 
  272.      * @return 
  273.      */  
  274.     protected boolean isSlideToBottom(RecyclerView recyclerView) {  
  275.         if (recyclerView == nullreturn  false;  
  276.         if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange())  
  277.             return true;  
  278.         return false;  
  279.     }  
  280.   
  281.     /** 
  282.      * 加载更多回调接口 
  283.      */  
  284.     public interface OnLoadMoreListener  
  285.     {  
  286.         void onLoadMore();  
  287.     }  
  288.   
  289. }  
package com.ywl5320.recyclerveiwdemo;

import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by ywl on 2017-7-23.
 */

public class WapHeaderAndFooterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private int headtype = 0x11111;
    private int normaltype = 0x11112;
    private int foottype = 0x11113;
    private View headerView;
    private View footerView;
    private RecyclerView.Adapter badapter;//目标adapter
    private OnLoadMoreListener onloadMoreListener;


    public WapHeaderAndFooterAdapter(RecyclerView.Adapter badapter) {
        this.badapter = badapter;
    }

    public void addHeader(View header)
    {
        headerView = header;
    }

    public void addFooter(View footer)
    {
        footerView = footer;
    }

    //实现加载更多接口
    public void setOnloadMoreListener(final OnLoadMoreListener onloadMoreListener, RecyclerView recyclerView) {
        this.onloadMoreListener = onloadMoreListener;
        if(recyclerView != null && onloadMoreListener != null)
        {
            recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                }

                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    if(isSlideToBottom(recyclerView))
                    {
                        if(onloadMoreListener != null)
                        {
                            onloadMoreListener.onLoadMore();
                        }
                    }
                }
            });
        }
    }

    /**
     * 根据头部尾部返回相应的type,这里if else没有简写,方便看逻辑
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {

        if(headerView != null && footerView != null)//同时加了头部和尾部
        {
            if(position == 0)//当position为0时,展示header
            {
                return headtype;
            }
            else if(position == getItemCount() - 1)//当position为最后一个时,展示footer
            {
                return foottype;
            }
            else//其他时候就展示原来adapter的
            {
                return normaltype;
            }
        }
        else if(headerView != null) {//只有头部
            if (position == 0)
                return headtype;
            return normaltype;
        }
        else if(footerView != null)//只有尾部
        {
            if(position == getItemCount() - 1)
            {
                return foottype;
            }
            else
            {
                return normaltype;
            }
        }
        else {
            return normaltype;
        }
    }

    /**
     * 这里就根据getItemViewType返回的值来返回相应的ViewHolder
     * 头部和尾部的ViewHolder只是一个集成RecyclerView.ViewHolder的简单默认类,里面并没有任何处理。
     * 这样就完成了类型的返回了(需注意为什么这样做)
     * @param parent
     * @param viewType
     * @return
     */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if(viewType == headtype)//返回头部的ViewHolder
            return new HeaderViewHolder(headerView);
        else if(viewType == foottype)//返回尾部的ViewHolder
            return new FoogerViewHolder(footerView);//其他就直接返回传入的adapter的ViewHolder
        return badapter.onCreateViewHolder(parent, viewType);
    }

    /**
     * 绑定ViewHolder,当时header或footer时,直接返回,因为不用绑定,
     * 当是传入的adapter时,就直接调用adapter.onBindViewHolder就行了
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if(headerView != null && footerView != null)//有头部和尾部
        {
            if(position == 0)//头部直接返回,无需绑定
            {
                return;
            }
            else if(position == getItemCount() -1)//尾部直接返回,也无需绑定
            {
                return;
            }
            else
            {
                badapter.onBindViewHolder(holder, position - 1);//其他就调用adapter的绑定方法
            }
        }
        else if(headerView != null)
        {
            if(position == 0)
            {
                return;
            }
            else
            {
                badapter.onBindViewHolder(holder, position - 1);
            }
        }
        else if(footerView != null)
        {
            if(position == getItemCount() - 1)
            {
                return;
            }
            else
            {
                badapter.onBindViewHolder(holder, position);
            }
        }
        else
        {
            badapter.onBindViewHolder(holder, position);
        }
    }

    /**
     * 返回item的数量,
     * @return
     */
    @Override
    public int getItemCount() {

        if(headerView != null && footerView != null)//有头部和尾部,就多了2
        {
            return badapter.getItemCount() + 2;
        }
        else if(headerView != null)//只有头部多了1
        {
            return badapter.getItemCount() + 1;
        }
        else if(footerView != null)//只有尾部也多了1
        {
            return badapter.getItemCount() + 1;
        }
        return badapter.getItemCount();//其他就是默认的值, 不多也不少
    }

    /**
     * 头部的ViewHolder
     */
    private class HeaderViewHolder extends RecyclerView.ViewHolder
    {
        public HeaderViewHolder(View itemView) {
            super(itemView);
        }
    }

    /**
     * 尾部的ViewHolder
     */
    private class FoogerViewHolder extends RecyclerView.ViewHolder
    {
        public FoogerViewHolder(View itemView) {
            super(itemView);
        }
    }

    /**
     * 处理当时Gridview类型的效果时,也把头部和尾部设置成一整行(这就是RecyclerView的其中一个优秀之处,列表的每行可以不同数量的列)
     * @param recyclerView
     */
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if(layoutManager instanceof GridLayoutManager)
        {
            /**
             * getSpanSize的返回值的意思是:position位置的item的宽度占几列
             * 比如总的是4列,然后头部全部显示的话就应该占4列,此时就返回4
             * 其他的只占一列,所以就返回1,剩下的三列就由后面的item来依次填充。
             */
            ((GridLayoutManager) layoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    if(headerView != null && footerView != null)
                    {
                        if(position == 0)
                        {
                            return ((GridLayoutManager) layoutManager).getSpanCount();
                        }
                        else if(position == getItemCount() - 1) {
                            return ((GridLayoutManager) layoutManager).getSpanCount();
                        }
                        else
                        {
                            return 1;
                        }
                    }
                    else if(headerView != null) {
                        if (position == 0) {
                            return ((GridLayoutManager) layoutManager).getSpanCount();
                        }
                        return 1;
                    }
                    else if(footerView != null)
                    {
                        if(position == getItemCount() - 1)
                        {
                            return ((GridLayoutManager) layoutManager).getSpanCount();
                        }
                        return 1;
                    }
                    return 1;
                }
            });
        }
    }

    /**
     * 判断是否到底部了
     * @param recyclerView
     * @return
     */
    protected boolean isSlideToBottom(RecyclerView recyclerView) {
        if (recyclerView == null) return false;
        if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange())
            return true;
        return false;
    }

    /**
     * 加载更多回调接口
     */
    public interface OnLoadMoreListener
    {
        void onLoadMore();
    }

}

三:最后的调用方式为

  1. setContentView(R.layout.activity_main);  
  2.         recyclerView = (RecyclerView) findViewById(R.id.recyclerview);  
  3.         datas = new ArrayList<>();  
  4.         for(int i = 0; i <  60; i++)  
  5.         {  
  6.             datas.add(i + "");  
  7.         }  
  8.         myAdapter = new MyAdapter(this, datas);  
  9.         headerAndFooterAdapter = new WapHeaderAndFooterAdapter(myAdapter);  
  10.   
  11. //        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);  
  12. //        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);  
  13. //        recyclerView.setLayoutManager(linearLayoutManager);  
  14.   
  15.         GridLayoutManager gridLayoutManager = new GridLayoutManager(this 3);  
  16.         recyclerView.setLayoutManager(gridLayoutManager);  
  17.   
  18.         View header = LayoutInflater.from(this).inflate(R.layout.header_view, recyclerView, false);  
  19.         View footer = LayoutInflater.from(this).inflate(R.layout.footer_view, recyclerView, false);  
  20.   
  21.         headerAndFooterAdapter.addHeader(header);  
  22.         headerAndFooterAdapter.addFooter(footer);  
  23.   
  24.         recyclerView.setAdapter(headerAndFooterAdapter);  
  25.         headerAndFooterAdapter.setOnloadMoreListener(new WapHeaderAndFooterAdapter.OnLoadMoreListener() {  
  26.             @Override  
  27.             public void onLoadMore() {  
  28.                 Toast.makeText(MainActivity.this"加载更多", Toast.LENGTH_SHORT).show();  
  29.             }  
  30.         }, recyclerView);  
setContentView(R.layout.activity_main);
        recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
        datas = new ArrayList<>();
        for(int i = 0; i < 60; i++)
        {
            datas.add(i + "");
        }
        myAdapter = new MyAdapter(this, datas);
        headerAndFooterAdapter = new WapHeaderAndFooterAdapter(myAdapter);

//        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
//        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
//        recyclerView.setLayoutManager(linearLayoutManager);

        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 3);
        recyclerView.setLayoutManager(gridLayoutManager);

        View header = LayoutInflater.from(this).inflate(R.layout.header_view, recyclerView, false);
        View footer = LayoutInflater.from(this).inflate(R.layout.footer_view, recyclerView, false);

        headerAndFooterAdapter.addHeader(header);
        headerAndFooterAdapter.addFooter(footer);

        recyclerView.setAdapter(headerAndFooterAdapter);
        headerAndFooterAdapter.setOnloadMoreListener(new WapHeaderAndFooterAdapter.OnLoadMoreListener() {
            @Override
            public void onLoadMore() {
                Toast.makeText(MainActivity.this, "加载更多", Toast.LENGTH_SHORT).show();
            }
        }, recyclerView);
        这里recyclerView.setAdapter中的adapter就是我们封装的adapter 了,这里有一点需要注意就是创建headerview的时候Inflate时,parent需要传入recyclerView对象才能时布局matchparent起效果,具体原因在Inflate源码里面能找到的,这里我就不细说了。

        好了外面已经是风云雷电交加,中国之声的《千里共良宵》我也已经听第二遍了,也该睡了。

Demo下载地址:GitHub:https://github.com/wanliyang1990/RecyclerViewHeaderAndFooter