学而实习之 不亦乐乎

Android:为RecyclerView添加Header和footer

2021-07-28 22:06:14

一、简介

一般情况下 RecyclerView 中 Header 和 Footer 很多情况下是辅助,比如 Header 通常用于做广告,而 Footer 更多的是为了显示下拉加载更多作为一个可视化组件来显示加载情况,提升用户体验。

二、实现

RecyclerView 的使用无非就是那三步:

  1. 初始化RecyclerView;
  2. 初始化数据,并且将数据通过Adapter装在到View中;
  3. 通过setAdapter方法,将Adapter绑定到RecyclerView中。

代码如下:

(1)主布局layout_main.xml: 只是添加了一个RecyclerView而已

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" 
        android:layout_width="match_parent"  
        android:layout_height="match_parent"  
        android:paddingBottom="@dimen/activity_vertical_margin" 
        android:paddingLeft="@dimen/activity_horizontal_margin" 
        android:paddingRight="@dimen/activity_horizontal_margin" 
        android:paddingTop="@dimen/activity_vertical_margin" 
        tools:context="com.study.wnw.recyclerviewheaderfooter.MainActivity"> 
        <android.support.v7.widget.RecyclerView 
                android:id="@+id/recyclerview" 
                android:layout_width="match_parent" 
                android:layout_height="match_parent"/> 
</RelativeLayout>

(2)RecyclerView中ListView的Item布局list_Item.xml: 只是添加了一个TextView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
         xmlns:android="http://schemas.android.com/apk/res/android" 
         android:orientation="vertical"  
         android:layout_width="match_parent" 
         android:layout_height="50dp"> 
         <TextView 
                 android:id="@+id/item" 
                android:layout_width="match_parent"  
                android:layout_height="match_parent"  
                android:textSize="20sp" 
                android:textColor="@color/colorAccent" 
                android:gravity="center"  
                android:background="#08e630"/> 
</LinearLayout>

(3)HeaderView和FooterView的布局文件,也是一个TextView, 这里只贴出了HeaderView的布局,FooterView的布局文件和FooterView的一样:

HeaderView的布局文件: header.xml:

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"            
        android:orientation="vertical"   
        android:layout_width="match_parent"   
        android:layout_height="100dp"> 
        <TextView        
                android:id="@+id/header" 
                android:layout_width="match_parent" 
                android:layout_height="match_parent" 
                android:text="我是Header" 
                android:textSize="30sp" 
                android:textColor="#fde70b0b" 
                android:background="#f9777979"  
                android:gravity="center"/> 
</LinearLayout>

(4) MainActivity.java中的内容为:

public class MainActivity extends Activity {     
     private RecyclerView mRecyclerView;     
     private MyAdapter mMyAdapter;     
     private List<String> mList;     
 
     @Override      
     protected void onCreate(Bundle savedInstanceState) { 
         super.onCreate(savedInstanceState); 
         setContentView(R.layout.activity_main);  
 
         //RecyclerView三部曲+LayoutManager        
         mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview); 
         LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); 
         mRecyclerView.setLayoutManager(linearLayoutManager); 
         initData(); 
         mMyAdapter = new MyAdapter(mList);  
         mRecyclerView.setAdapter(mMyAdapter);    


        //为RecyclerView添加HeaderView和FooterView  
         setHeaderView(mRecyclerView); 
         setFooterView(mRecyclerView);  
    }       

    //初始化RecyclerView中每个item的数据 
    private void initData(){ 
        mList = new ArrayList<String>(); 
        for (int i = 0; i < 20; i++){  
            mList.add("item" + i);  
        }   
    }    

    private void setHeaderView(RecyclerView view){  
        View header = LayoutInflater.from(this).inflate(R.layout.header, view, false); 
         mMyAdapter.setHeaderView(header); 
    }      

    private void setFooterView(RecyclerView view){  
        View footer = LayoutInflater.from(this).inflate(R.layout.footer, view, false);         
        mMyAdapter.setFooterView(footer);  
    } 
}

从上面的代码中,我们可以看到,我们在MainActivity中做了两件事:

  1. 初始化RecyclerView相关的View, Adapter, data。
  2. 通过我们自定义的Adapter的setHeaderView()和setFooterView()方法为RecyclerView添加HeaderView和FooterView。

(5) MyAdapter.java的代码

public class MyAdapter extendsRecyclerView.Adapter<RecyclerView.ViewHolder> {   
    public static final int TYPE_HEADER = 0;  //说明是带有Header的  
    public static final int TYPE_FOOTER = 1;  //说明是带有Footer的  
    public static final int TYPE_NORMAL = 2;  //说明是不带有header和footer的


    //获取从Activity中传递过来每个item的数据集合  
    private List<String> mDatas;
    //HeaderView, FooterView   
    private View mHeaderView;   
    private View mFooterView;   

    //构造函数   
    public MyAdapter(List<String> list){       
        this.mDatas = list;   
    }   

    //HeaderView和FooterView的get和set函数   
    public View getHeaderView() {       
        return mHeaderView;   
    }   
    public void setHeaderView(View headerView) {       
        mHeaderView = headerView;       
        notifyItemInserted(0);   
    }   
    public View getFooterView() {       
        return mFooterView;   
    }   
    public void setFooterView(View footerView) {       
        mFooterView = footerView;       
        notifyItemInserted(getItemCount()-1);   
    }  

    /** 重写这个方法,很重要,是加入Header和Footer的关键,我们通过判断item的类型,从而绑定不同的view    * */  
    @Override
    public int getItemViewType(int position) {        
        if (mHeaderView == null && mFooterView == null){           
            return TYPE_NORMAL;      
        }       
        if (position == 0){           
            //第一个item应该加载Header           
            return TYPE_HEADER;      
        }      
        if (position == getItemCount()-1){          
            //最后一个,应该加载Footer          
            return TYPE_FOOTER;      
        }       
        return TYPE_NORMAL;  
    }   

     //创建View,如果是HeaderView或者是FooterView,直接在Holder中返回          
     @Override   
     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {       
        if(mHeaderView != null && viewType == TYPE_HEADER) {           
            return new ListHolder(mHeaderView);      
        }       
        if(mFooterView != null && viewType == TYPE_FOOTER){           
            return new ListHolder(mFooterView);      
        }       
        View layout = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);       
        return new ListHolder(layout);   
    }   

    //绑定View,这里是根据返回的这个position的类型,从而进行绑定的,   HeaderView和FooterView, 就不同绑定了   
    @Override   
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {       
        if(getItemViewType(position) == TYPE_NORMAL){           
            if(holder instanceof ListHolder) {               
                //这里加载数据的时候要注意,是从position-1开始,因为position==0已经被header占用了               
                ((ListHolder) holder).tv.setText(mDatas.get(position-1));               
                return;           
            }           
            return;       
        }else if(getItemViewType(position) == TYPE_HEADER){           
            return;           
        }else{          
           return;      
         }  
      }   

    //在这里面加载ListView中的每个item的布局   
    class ListHolder extends RecyclerView.ViewHolder{       
        TextView tv;       
        public ListHolder(View itemView) {           
            super(itemView);           
            //如果是headerview或者是footerview,直接返回           
            if (itemView == mHeaderView){               
                return;           
            }           
            if (itemView == mFooterView){               
                return;           
            }           
            tv = (TextView)itemView.findViewById(R.id.item);       
         }   
    }   

    //返回View中Item的个数,这个时候,总的个数应该是ListView中Item的个数加上HeaderView和FooterView   
    @Override   
    public int getItemCount() {       
        if(mHeaderView == null && mFooterView == null){           
            return mDatas.size();       
        }else if(mHeaderView == null && mFooterView != null){           
            return mDatas.size() + 1;       
        }else if (mHeaderView != null && mFooterView == null){           
            return mDatas.size() + 1;       
        }else {           
            return mDatas.size() + 2;       
        }   
    }
}

从上面的MyAdapter类中,有setHeaderView()和setFooterView()两个方法,我们就是通过这两个方法在Activity设置headerView和footerView的。