欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android中封装RecyclerView实现添加头部和底部示例代码

程序员文章站 2023-12-04 09:59:40
前言 我们大家都知道listview具有添加头部和添加底部的方法,但是recyclerview并没有这样子的方法。所以recyclerview是不能添加底部和头部的,但是...

前言

我们大家都知道listview具有添加头部和添加底部的方法,但是recyclerview并没有这样子的方法。所以recyclerview是不能添加底部和头部的,但是能不能仿造listview来实现recyclerview添加头部和底部呢?答案当然是可行的。本文就来给大家介绍了关于android封装recyclerview添加头部和底部的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

首先看下实现的效果:

Android中封装RecyclerView实现添加头部和底部示例代码

代码如下:

public class wrapmyrecyclerview extends recyclerview {

 private adapter madapter;
 private arraylist<view> mheaderviewinfos = new arraylist<>();//保存headerview
 private arraylist<view> mfooterviewinfos = new arraylist<>();//保存footerview

 public wrapmyrecyclerview(context context) {
  super(context);
 }

 public wrapmyrecyclerview(context context, @nullable attributeset attrs) {
  super(context, attrs);
 }

 public wrapmyrecyclerview(context context, @nullable attributeset attrs, int defstyle) {
  super(context, attrs, defstyle);
 }

 /**
  * 添加headerview
  * @param v
  */
 public void addheaderview(view v) {
  mheaderviewinfos.add(v);
  // wrap the adapter if it wasn't already wrapped.
  if (madapter != null) {
   if (!(madapter instanceof recyclerheaderviewlistadapter)) {
    wrapheaderlistadapterinternal();
   }
  }
 }

 /**
  * 添加一个footerview
  * @param v
  */
 public void addfooterview(view v) {
  mfooterviewinfos.add(v);
  // wrap the adapter if it wasn't already wrapped.
  if (madapter != null) {
   if (!(madapter instanceof recyclerheaderviewlistadapter)) {
    wrapheaderlistadapterinternal();
   }
  }
 }

 /**
  * 设置一个adapter
  * @param adapter
  */
 @override
 public void setadapter(adapter adapter) {

  if (mheaderviewinfos.size() > 0 || mfooterviewinfos.size() > 0) {
   madapter = wrapheaderlistadapterinternal(mheaderviewinfos, mfooterviewinfos, adapter);
  } else {
   madapter = adapter;
  }
  super.setadapter(madapter);
 }

 private void wrapheaderlistadapterinternal() {
  madapter = wrapheaderlistadapterinternal(mheaderviewinfos, mfooterviewinfos, madapter);
 }

 /**
  * 新建一个recyclerheaderviewlistadapter对象
  * 最终的adapter实现它
  * @param headerviewinfos
  * @param footerviewinfos
  * @param adapter
  * @return
  */
 protected recyclerheaderviewlistadapter wrapheaderlistadapterinternal(
   arraylist<view> headerviewinfos,
   arraylist<view> footerviewinfos,
   adapter adapter) {
  return new recyclerheaderviewlistadapter(headerviewinfos, footerviewinfos, adapter);
 }

}

这就是封装的recyclerview,里面主要有三个方法addheaderview、 addfooterview和重写的setadapter。这里的唯一的思想就是偷梁换柱,当我们添加头部、尾部或者设置adapter时,真正的adapter并不是我们传入的adapter,而是重新new 了一个recyclerheaderviewlistadapter。这才是recyclerview最终设置的adapter。

其实我们看到listview也是通过这样子的思想来添加头部和尾部的。

Android中封装RecyclerView实现添加头部和底部示例代码

这就是listview的addheaderview方法,它会偷偷的创建headerviewlistadapter这个adapter。最终添加的header和footer在headerviewlistadapter里面实现。

public class recyclerheaderviewlistadapter extends recyclerview.adapter {

 private final arraylist<view> mheaderviewinfos;//保存headerview数据
 private final arraylist<view> mfooterviewinfos;//保存footerview数据
 private recyclerview.adapter madapter;   //用户自己构造的adapter
 private static final int recycler_header_view = 0x001;//headerview类型
 private static final int recycler_footer_view = 0x002;//footerview类型


 /**
  * 构造方法
  * 初始化
  * @param headerviewinfos
  * @param footerviewinfos
  * @param adapter
  */
 public recyclerheaderviewlistadapter(arraylist<view> headerviewinfos,
           arraylist<view> footerviewinfos,
           recyclerview.adapter adapter) {

  madapter = adapter;
  if (headerviewinfos == null) {
   mheaderviewinfos = new arraylist<>();
  } else {
   mheaderviewinfos = headerviewinfos;
  }

  if (footerviewinfos == null) {
   mfooterviewinfos = new arraylist<>();
  } else {
   mfooterviewinfos = footerviewinfos;
  }
 }

 /**
  * 根据getitemviewtype返回的条目类型
  * 创建不同的itemview
  * 传入的adapter,回调它的oncreateviewholder即可
  * @param parent
  * @param viewtype
  * @return
  */
 @override
 public recyclerview.viewholder oncreateviewholder(viewgroup parent, int viewtype) {
  if (viewtype == recycler_header_view){
   return new headerviewlayout(mheaderviewinfos.get(0));
  }else if (viewtype == recycler_footer_view){
   return new headerviewlayout(mfooterviewinfos.get(0));
  }
  return madapter.oncreateviewholder(parent,viewtype);
 }

 /**
  * 绑定数据
  * headerview和footerview不需要绑定数据,直接return即可
  * 传入的adapter需要回调它的onbindviewholder即可
  * @param holder
  * @param position
  */
 @override
 public void onbindviewholder(recyclerview.viewholder holder, int position) {
  //header
  int numheaders = getheaderscount();
  if (position < numheaders) {
   return ;
  }
  //adapter body
  final int adjposition = position - numheaders;
  int adaptercount = 0;
  if (madapter != null) {
   adaptercount = madapter.getitemcount();
   if (adjposition < adaptercount) {
    madapter.onbindviewholder(holder, adjposition);
    return ;
   }
  }
  //footer
 }

 /**
  * 返回条目的类型
  * 传入的adapter,回调它的getitemviewtype即可
  * @param position
  * @return
  */
 @override
 public int getitemviewtype(int position) {
  // header
  int numheaders = getheaderscount();
  if (position < numheaders) {
   return recycler_header_view;
  }
  // adapter
  final int adjposition = position - numheaders;
  int adaptercount = 0;
  if (madapter != null) {
   adaptercount = madapter.getitemcount();
   if (adjposition < adaptercount) {
    return madapter.getitemviewtype(position);
   }
  }
  // footer (off-limits positions will throw an indexoutofboundsexception)
  return recycler_footer_view;
 }

 /**
  * 总条目即:footerview的条目+headerview的条目+穿入的adapter条目
  * @return
  */
 @override
 public int getitemcount() {
  if (madapter != null) {
   return getfooterscount() + getheaderscount() + madapter.getitemcount();
  } else {
   return getfooterscount() + getheaderscount();
  }
 }

 /**
  * 获取headerview的条目
  * @return
  */
 public int getheaderscount() {
  return mheaderviewinfos.size();
 }

 /**
  * 获取footervie的条目
  * @return
  */
 public int getfooterscount() {
  return mfooterviewinfos.size();
 }

 /**
  * 这是footerview和headerview的viewholder需要
  * 这里只是提供一个构造器即可,实际上用处不大
  */
 private static class headerviewlayout extends recyclerview.viewholder{

  public headerviewlayout(view itemview) {
   super(itemview);
  }
 }

}

这是实现添加header、footer和传入adapter的recyclerheaderviewlistadapter。具体的逻辑都在文件的注释里面有说明。逻辑是仿造listview的headerviewlistadapter来实现的。

其实就是创建一个adapter,然后根据不同的条目类型来创建条目和绑定条目的数据即可。

<?xml version="1.0" encoding="utf-8"?>
<linearlayout
 xmlns: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:orientation="vertical"
 tools:context="com.wrap.recycler.wraprecyclerviewactivity">

 <com.lwj.wrap.recycler.wrapmyrecyclerview
  android:id="@+id/wrap_recyclerview"
  android:layout_width="match_parent"
  android:layout_height="match_parent"/>

</linearlayout>

这是布局文件

public class wraprecyclerviewactivity extends appcompatactivity {
 private wrapmyrecyclerview mrecyclerview;
 private myadapter mmyadapter;
 private list<string> mlist01 = new arraylist<>();
 private static final int wc = viewgroup.layoutparams.wrap_content;
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_wrap_recycler_view);
  getdata();
  mrecyclerview = (wrapmyrecyclerview) this.findviewbyid(r.id.wrap_recyclerview);
  mrecyclerview.setlayoutmanager(new linearlayoutmanager(this));

  //加入headerview
  viewgroup.layoutparams params = new viewgroup.layoutparams(wc,wc);
  imageview headerview = new imageview(this);
  headerview.setimageresource(r.drawable.timg);
  headerview.setlayoutparams(params);
  mrecyclerview.addheaderview(headerview);
  //设置adapter
  mmyadapter = new myadapter(this,mlist01);
  mrecyclerview.setadapter(mmyadapter);
  //加入footerview
  params = new viewgroup.layoutparams(wc,wc);
  imageview footerview = new imageview(this);
  footerview.setimageresource(r.drawable.hhfj);
  footerview.setlayoutparams(params);
  mrecyclerview.addfooterview(footerview);
  mmyadapter.notifydatasetchanged();

 }
 public void getdata() {
  for (int i = 0; i < 3; i++) {
   string data ="adapter...." + i;
   mlist01.add(data);
  }
 }
}

使用直接调用addheaderview、addfooterview即可。

除了这种方式来实现addheaderview和addfooterview,另外一种方式就是封装adapter来实现,原理还是保持不变:根据不同的条目类型来创建条目和绑定条目的数据。

public class mycirclerecycviewadapter extends recyclerview.adapter {
 public list<circleinfo.circlepageinfo> infos = null;
 private context mcontext;
 private listviewimgloader mloader;
 private view view_footer;//尾部
 private view view_header;//头部
 //type
 private int type_normal = 1000;
 private int type_header = 1001;
 private int type_footer = 1002;
 private int tagtype = type_normal;

 public mycirclerecycviewadapter(context context,list<circleinfo.circlepageinfo> datas) {
  this.infos = datas;
  this.mcontext = context;
  mloader = new listviewimgloader();
  mloader.setmemorycachesize(1024 * 1024);
  mloader.setvisibleitemcount(12);
 }

 @override
 public recyclerview.viewholder oncreateviewholder(viewgroup parent, int viewtype) {
  if (viewtype == type_footer) {
   tagtype = type_footer;
   return new mycircleitemholder(view_footer);
  } else if (viewtype == type_header) {
   tagtype = type_header;
   return new mycircleitemholder(view_header);
  } else {
   tagtype = type_normal;
   view view = layoutinflater.from(mcontext).inflate(r.layout.circle_gridview_items, parent,false);
   return new mycircleitemholder(view);
  }
 }

 @override
 public void onbindviewholder(recyclerview.viewholder holder, int position) {
  if (!isheaderview(position) && !isfooterview(position)) {
   if (haveheaderview()) position--;
   mycircleitemholder viewholder = (mycircleitemholder)holder;
   circleinfo.circlepageinfo minfo = infos.get(position);
   setdata(viewholder,minfo);
  }
 }

 @override
 public int getitemcount() {
  int count = (infos == null ? 0 : infos.size());
  if (view_footer != null) {
   count++;
  }
  if (view_header != null) {
   count++;
  }
  return count;
 }

 @override
 public int getitemviewtype(int position)
 {
  if (isheaderview(position)) {
   return type_header;
  } else if (isfooterview(position)) {
   return type_footer;
  } else {
   return type_normal;
  }
 }
 public void addheaderview(view headerview) {
  if (haveheaderview()) {
   throw new illegalstateexception("hearview has already exists!");
  } else {
   //避免出现宽度自适应
   viewgroup.layoutparams params = new viewgroup.layoutparams(utils.getrealpixel(30), utils.getrealpixel(230));
   headerview.setlayoutparams(params);
   view_header = headerview;
   notifyiteminserted(0);
  }
 }
 public void addfooterview(view footerview) {
  if (havefooterview()) {
   throw new illegalstateexception("footerview has already exists!");
  } else {
   viewgroup.layoutparams params = new viewgroup.layoutparams(viewgroup.layoutparams.match_parent, viewgroup.layoutparams.wrap_content);
   footerview.setlayoutparams(params);
   view_footer = footerview;
//   ifgridlayoutmanager();
   notifyiteminserted(getitemcount() - 1);
  }
 }

 private boolean haveheaderview() {
  return view_header != null;
 }

 public boolean havefooterview() {
  return view_footer != null;
 }

 private boolean isheaderview(int position) {
  return haveheaderview() && position == 0;
 }

 private boolean isfooterview(int position) {
  return havefooterview() && position == getitemcount() - 1;
 }


 private void setdata(final mycircleitemholder viewholder, final circleinfo.circlepageinfo minfo) {
  if(minfo == null || minfo == viewholder.taginfo)
  {
   return;
  }else{
   viewholder.taginfo = minfo;
   if(!strutils.isenpty(minfo.thread_unread)){
    if(minfo.thread_unread.equals("0")){
     viewholder.threaduunreadtv.setvisibility(view.invisible);
    }else{
     viewholder.threaduunreadtv.setvisibility(view.visible);
     viewholder.threaduunreadtv.settext(minfo.thread_unread);
    }
   }else{
    viewholder.threaduunreadtv.setvisibility(view.invisible);
   }

   if (!textutils.isempty(viewholder.tagurl)){
    if(minfo.circle_img_path != null && !(minfo.circle_img_path.equals(viewholder.tagurl))){
     setimage(viewholder.mimageview,minfo.circle_img_path);
    }
   }else{
    setimage(viewholder.mimageview,minfo.circle_img_path);
   }
   if (!textutils.isempty(minfo.circle_img_path)){
    viewholder.tagurl = minfo.circle_img_path;
   }
   if(minfo.circlename != null){
    if(minfo.circlename.length() > 5){
     string s = minfo.circlename.substring(0,5) + "...";
     viewholder.textview.settext(s);
    }else{
     viewholder.textview.settext(minfo.circlename);
    }
   }

  }
 }

 private void setimage(final colorfilterimageview mimageview, final string imgurl){
  mimageview.setbackgroundcolor(0xffadadad);
  mimageview.setimagebitmap(null);
  if(!textutils.isempty(imgurl))
  {
   mloader.loadimage(mimageview.hashcode(), imgurl, 300, new dnimg.ondnimglistener()
   {

    @override
    public void onprogress(string url, int downloadedsize, int totalsize)
    {
     // todo auto-generated method stub

    }

    @override
    public void onfinish(string url, string file, bitmap bmp)
    {
     if(url.equals(imgurl))
     {
      mimageview.setimagebitmap(bmp);
     }
    }
   });
  }else{
   mimageview.setbackgroundcolor(0xffadadad);
   mimageview.setimagebitmap(null);
  }
 }


 class mycircleitemholder extends recyclerview.viewholder{
  private colorfilterimageview mimageview;
  private textview textview;
  private circleinfo.circlepageinfo taginfo;
  private string tagurl;
  private textview threaduunreadtv;

  public mycircleitemholder(final view itemview) {
   super(itemview);
   if(tagtype == type_normal){
    mimageview = (colorfilterimageview)itemview.findviewbyid(r.id.quan_icon);
    mimageview.setscaletype(imageview.scaletype.center_crop);
    textview = (textview)itemview.findviewbyid(r.id.quan_name);
    threaduunreadtv = (textview)itemview.findviewbyid(r.id.quan_num);
    mimageview.setonclicklistener(new view.onclicklistener() {
     @override
     public void onclick(view v) {
      if (mlistener != null){
       mlistener.oncliitem(itemview,taginfo,threaduunreadtv);
      }
     }
    });
   }

  }
 }
 public onclickmycircleitemlistener mlistener;
 public void setonclickmycircleitemlistener(onclickmycircleitemlistener l){
  this.mlistener = l;
 }
 public interface onclickmycircleitemlistener{
  void oncliitem(view view,circleinfo.circlepageinfo info,view threadnumtv);
 }

 public void pauseloader(){
  if(mloader != null)
  {
   mloader.pause();
  }
 }
 public void resumeloader(){
  if(mloader != null)
  {
   mloader.resume();
  }
 }
 public void closeloader(){
  if(mloader != null)
  {
   mloader.close();
  }
 }

}

总结

以上就是这篇文章的全部内容了,希望本文的内容对各位android开发者们的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。