Android中封装RecyclerView实现添加头部和底部示例代码
前言
我们大家都知道listview具有添加头部和添加底部的方法,但是recyclerview并没有这样子的方法。所以recyclerview是不能添加底部和头部的,但是能不能仿造listview来实现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也是通过这样子的思想来添加头部和尾部的。
这就是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开发者们的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。