Android仿XListView支持下拉刷新和上划加载更多的自定义RecyclerView
首先给大家展示下效果图,感觉还不错,请继续往下阅读:
下拉刷新:
上划加载
在项目更新的过程中,遇到了一个将xlistview换成recyclerview的需求,而且更换完之后大体效果不能变,但是对于下拉刷新这样的效果,谷歌给出的解决方案是把recyclerview放在一个swiperefreshlayout中,但是这样其实是拉下一个小圆形控件实现的,和xlistview的header效果不同。在网上找了很多的别人代码,都没有实现我想要的效果,于是自己动手写了一个。
具体实现的效果有以下几条
下拉刷新功能:
1、实现一个有弹性的拖出效果:思路参考xlistview,recyclerview的position=0的位置放一个header布局,这个布局的margin top默认为负的布局高度,所以这块布局就一直处于屏幕外部,在下拉的时候通过ontouchlistener根据手指的移动动态修改margin top,慢慢的拖出,当拖出的距离也就是margin top变为正数以后,就盖面header布局的状态,改变箭头的方向并改变提示语
2、实现有弹性的回弹效果:用timertask写了一个动态修改的header布局的margin top的动画,每隔一定的时间减小margin top的值,当用户松手的时候通过一个函数updateheaderheight()来执行这个动画。
3、实现用户非手动拖拉的自动刷新效果:这个recyclerview还有一个方法叫forcerefresh(),就是不需要用户手动下拉,头部自己滚动出来,然后刷新完再自己收回去,自动下拉也是用一个timertask每隔十几毫秒增加margin top的值让头部慢慢露出来
上划加载更多功能:
1、实现滚动到底部自动停住效果: 有时候recyclerview滚动太快,滚到底部的时候会根据惯性向上飘,这个地方到底的时候监控recyclerview滚动速度,如果非常快说明是惯性滚动,就不修改footer布局的高度
2、实现向上拖动效果:复写了recyclerview的onscrolllistener,在手指向上滚动的时候,通过updatefooterheight()方法动态修改底部footerview的margin bottom,同headerview一样,在手指移动的时候让这个margin跟着变大,以增加footer布局的高度,而且手指移动的越网上,增加的margin的高度就越小,实现一个有弹性的上拉效果,防止误操作。
3、实现自动回弹的效果:通过监控footer布局的margin bottom来确定松手的时候是否需要开始刷新,如果margin bottom大于某个值得时候就修改footer布局的状态从normal变成ready,在ready状态下松手就开始刷新操作,回弹也像header布局一样通过一个timertask每隔十几毫秒修改margin的大小来实现回弹效果
注意事项:
1、为了实现头部和底部的代码分离,头部用的是ontouchlistener,底部用的是onscrolllistener
2、本recyclerview里面已经内置了一个layoutmanager,所以不要给recyclerview再设置layoutmanager,否则会出现头部不出来,下拉报空指针的情况,底部出现但是滑动没有效果
3、这个recyclerview内置了一个抽象类作为adapter,请继承这个内置的alxdragrecyclerviewadapter使用,或者按照这里面的逻辑重新写adapter
有其他的问题欢迎问我
4、一些常用的功能,比如设置该控件是否能够支持下拉加载和上拉刷新,等等api接口,请直接参考xlistview的用法即可
使用方法:
继承alxdragrecyclerviewadapter写一个adapter,然后写两个类分别实现onrefreshlistener和loadmorelistener,把具体的刷新逻辑写在里面,在准备好显示数据后调用adapter的notifydatasetchanged()方法或notifyiteminserted()方法,并执行该recyclerview的stoploadmore()方法和stoprefresh()方法。
下面是代码,这个控件有很多的内部类,包括头部,底部的布局控件(customdragheaderview,customdragfooterview),adapter,layoutmanager都已经以内部类的方式集成在里面,减少迁移时候的复杂度
import android.content.context; import android.graphics.color; import android.os.handler; import android.support.v7.widget.linearlayoutmanager; import android.support.v7.widget.recyclerview; import android.util.attributeset; import android.util.log; import android.view.layoutinflater; import android.view.motionevent; import android.view.view; import android.view.viewgroup; import android.view.windowmanager; import android.view.animation.animation; import android.view.animation.rotateanimation; import android.widget.imageview; import android.widget.linearlayout; import android.widget.textview; import com.xxx.app.r; import java.util.list; import java.util.timer; import java.util.timertask; /** * created by alex on 2016/1/27. */ public class alxrefreshloadmorerecyclerview extends recyclerview { private int footerheight = -1; linearlayoutmanager layoutmanager; // -- footer view private customdragrecyclerfooterview mfooterview; private boolean menablepullload; private boolean mpullloading; private boolean isbottom; private boolean misfooterready = false; private loadmorelistener loadmorelistener; // -- header view private customdragheaderview mheaderview; private boolean menablepullrefresh = true; private boolean misrefreshing; private boolean isheader; private boolean misheaderready = false; private timer timer; private float oldy; handler handler = new handler(); private onrefreshlistener refreshlistener; private alxdragrecyclerviewadapter adapter; private int maxpullheight = 50;//最多下拉高度的px值 private static final int header_height = 68;//头部高度68dp private static final int max_pull_length = 150;//最多下拉150dp private onclicklistener footerclicklistener; public alxrefreshloadmorerecyclerview(context context) { super(context); initview(context); } public alxrefreshloadmorerecyclerview(context context, attributeset attrs) { super(context, attrs); initview(context); } public alxrefreshloadmorerecyclerview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); initview(context); } public void setadapter(alxdragrecyclerviewadapter adapter){ super.setadapter(adapter); this.adapter = adapter; } public boolean ismpullloading() { return mpullloading; } public boolean ismisrefreshing() { return misrefreshing; } private void updatefooterheight(float delta) { if(mfooterview==null)return; int bottommargin = mfooterview.getbottommargin(); // log.i("alex3","初始delta是"+delta); if(delta>50)delta = delta/6; if(delta>0) {//越往下滑越难滑 if(bottommargin>maxpullheight)delta = delta*0.65f; else if(bottommargin>maxpullheight * 0.83333f)delta = delta*0.7f; else if(bottommargin>maxpullheight * 0.66667f)delta = delta*0.75f; else if(bottommargin>maxpullheight >> 1)delta = delta*0.8f; else if(bottommargin>maxpullheight * 0.33333f)delta = delta*0.85f; else if(bottommargin>maxpullheight * 0.16667f && delta > 20)delta = delta*0.2f;//如果是因为惯性向下迅速的俯冲 else if(bottommargin>maxpullheight * 0.16667f)delta = delta*0.9f; // log.i("alex3","bottommargin是"+mfooterview.getbottommargin()+" delta是"+delta); } int height = mfooterview.getbottommargin() + (int) (delta+0.5); if (menablepullload && !mpullloading) { if (height > 150){//必须拉超过一定距离才加载更多 // if (height > 1){//立即刷新 mfooterview.setstate(customdragrecyclerfooterview.state_ready); misfooterready = true; // log.i("alex2", "ready"); } else { mfooterview.setstate(customdragrecyclerfooterview.state_normal); misfooterready = false; // log.i("alex2", "nomal"); } } mfooterview.setbottommargin(height); } private void resetfooterheight() { int bottommargin = mfooterview.getbottommargin(); if (bottommargin > 20) { log.i("alex2", "准备重置高度,margin是" + bottommargin + "自高是" + footerheight); this.smoothscrollby(0,-bottommargin); //一松手就立即开始加载 if(misfooterready){ startloadmore(); } } } public void setloadmorelistener(loadmorelistener listener){ this.loadmorelistener = listener; } public void initview(context context){ layoutmanager = new linearlayoutmanager(context);//自带layoutmanager,请勿设置 layoutmanager.setorientation(linearlayoutmanager.vertical); windowmanager wm = (windowmanager) getcontext().getsystemservice(context.window_service); int height = wm.getdefaultdisplay().getheight(); layoutmanager.offsetchildrenvertical(height*2);//预加载2/3的卡片 this.setlayoutmanager(layoutmanager); // log.i("alex", "屏幕密度为" + getcontext().getresources().getdisplaymetrics().density); maxpullheight = dp2px(getcontext().getresources().getdisplaymetrics().density,max_pull_length);//最多下拉150dp this.footerclicklistener = new footerviewclicklistener(); this.addonscrolllistener(new recyclerview.onscrolllistener() { @override public void onscrollstatechanged(recyclerview recyclerview, int newstate) { super.onscrollstatechanged(recyclerview, newstate); switch (newstate){ case recyclerview.scroll_state_idle: // log.i("alex2", "停下了||放手了"); if(isbottom)resetfooterheight(); break; case recyclerview.scroll_state_dragging: // log.i("alex2", "开始拖了,现在margin是" + (mfooterview == null ? "" : mfooterview.getbottommargin())); break; case recyclerview.scroll_state_settling: // log.i("alex2", "开始惯性移动"); break; } } @override public void onscrolled(recyclerview recyclerview, int dx, int dy) { super.onscrolled(recyclerview, dx, dy); int lastitemposition = layoutmanager.findlastvisibleitemposition(); // log.i("alex2","menable是"+menablepullload+"lastitemposition是"+lastitemposition+" itemcount是"+layoutmanager.getitemcount()); if(lastitemposition == layoutmanager.getitemcount()-1 && menablepullload) {//如果到了最后一个 isbottom = true; mfooterview = (customdragrecyclerfooterview)layoutmanager.findviewbyposition(layoutmanager.findlastvisibleitemposition());//一开始还不能hide,因为hide得到最后一个可见的就不是footerview了 // log.i("alex2","到底啦!!"+"mfooterview是"+mfooterview); if(mfooterview!=null) mfooterview.setonclicklistener(footerclicklistener); if(footerheight==-1 && mfooterview!=null){ mfooterview.show(); mfooterview.setstate(customdragrecyclerfooterview.state_normal); footerheight = mfooterview.getmeasuredheight();//这里的测量一般不会出问题 // log.i("alex2", "底部高度为" + footerheight); } updatefooterheight(dy); }else if(lastitemposition == layoutmanager.getitemcount()-1 && menablepullload){//如果到了倒数第二个 startloadmore();//开始加载更多 } else { isbottom = false; } } }); } /** * 设置是否开启上拉加载更多的功能 * * @param enable */ public void setpullloadenable(boolean enable) { mpullloading = false; menablepullload = enable; if(adapter!=null)adapter.setpullloadmoreenable(enable);//adapter和recyclerview要同时设置 if(mfooterview==null)return; if (!menablepullload) { // this.smoothscrollby(0,-footerheight); mfooterview.hide(); mfooterview.setonclicklistener(null); mfooterview.setbottommargin(0); //make sure "pull up" don't show a line in bottom when listview with one page } else { mfooterview.show(); mfooterview.setstate(customdragrecyclerfooterview.state_normal); mfooterview.setvisibility(visible); //make sure "pull up" don't show a line in bottom when listview with one page // both "pull up" and "click" will invoke load more. mfooterview.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { startloadmore(); } }); } } /** * 停止loadmore */ public void stoploadmore() { if (mpullloading == true) { mpullloading = false; if(mfooterview==null)return; mfooterview.show(); mfooterview.setstate(customdragrecyclerfooterview.state_error); } } private void startloadmore() { if(mpullloading)return; mpullloading = true; if(mfooterview!=null)mfooterview.setstate(customdragrecyclerfooterview.state_loading); log.i("alex2", "现在开始加载"); misfooterready = false; if (loadmorelistener != null) { loadmorelistener.onloadmore(); } } /** * 在刷新时要执行的方法 */ public interface loadmorelistener{ public void onloadmore(); } /** * 点击loadmore后要执行的事件 */ class footerviewclicklistener implements onclicklistener { @override public void onclick(view v) { startloadmore(); } } private void updateheaderheight(float delta) { mheaderview = (customdragheaderview) layoutmanager.findviewbyposition(0); // log.i("alex2", "现在在头部!!!! header自高是" + mheaderview.getheight() + " margin 是" + mheaderview.gettopmargin());//自高一般不会算错 // log.i("alex2", "正在设置margin" + mheaderview.gettopmargin() +"delta是"+delta); if(delta>0){//如果是往下拉 int topmargin = mheaderview.gettopmargin(); if(topmargin>maxpullheight * 0.33333f)delta = delta*0.5f; else if(topmargin>maxpullheight * 0.16667f)delta = delta*0.55f; else if(topmargin>0)delta = delta*0.6f; else if(topmargin<0)delta = delta*0.6f;//如果没有被完全拖出来 mheaderview.settopmargin(mheaderview.gettopmargin() + (int)delta); } else{//如果是推回去 if(!misrefreshing || mheaderview.gettopmargin()>0) {//在刷新的时候不把margin设为负值以在惯性滑动的时候能滑回去 this.scrollby(0, (int) delta);//禁止既滚动,又同时减少触摸 // log.i("alex2", "正在往回推" + delta); mheaderview.settopmargin(mheaderview.gettopmargin() + (int) delta); } } if(mheaderview.gettopmargin()>0 && !misrefreshing){ misheaderready = true; mheaderview.setstate(customdragheaderview.state_ready); }//设置为ready状态 else if(!misrefreshing){ misheaderready = false; mheaderview.setstate(customdragheaderview.state_normal); }//设置为普通状态并且缩回去 } @override public void smoothscrolltoposition(final int position) { super.smoothscrolltoposition(position); final timer scrolltimer = new timer(); timertask timertask = new timertask() { @override public void run() { int bottomcardposition = layoutmanager.findlastvisibleitemposition(); if(bottomcardposition<position+1){//如果要向下滚 handler.post(new runnable() { @override public void run() { smoothscrollby(0,50); } }); }else if(bottomcardposition>position){//如果要向上滚 handler.post(new runnable() { @override public void run() { smoothscrollby(0,-50); } }); }else { if(scrolltimer!=null)scrolltimer.cancel(); } } }; scrolltimer.schedule(timertask,0,20); } /** * 在用户非手动强制刷新的时候,通过一个动画把头部一点点冒出来 */ private void smoothshowheader(){ if(mheaderview==null)return; // if(layoutmanager.findfirstvisibleitemposition()!=0){//如果刷新完毕的时候用户没有注视header // mheaderview.settopmargin(0); // return; // } if(timer!=null)timer.cancel(); final timertask timertask = new timertask() { @override public void run() { if(mheaderview==null){ if(timer!=null)timer.cancel(); return; } // log.i("alex2","topmargin是"+mheaderview.gettopmargin()+" height是"+mheaderview.getheight()); if(mheaderview.gettopmargin()<0){ handler.post(new runnable() { @override public void run() { if (misrefreshing) {//如果目前是ready状态或者正在刷新状态 mheaderview.settopmargin(mheaderview.gettopmargin() +2); } } }); } else if(timer!=null){//如果已经完全缩回去了,但是动画还没有结束,就结束掉动画 timer.cancel(); } } }; timer = new timer(); timer.scheduleatfixedrate(timertask,0,16); } /** * 在用户松手的时候让头部自动收缩回去 */ private void resetheaderheight() { if(mheaderview==null)mheaderview = (customdragheaderview) layoutmanager.findviewbyposition(0); if(layoutmanager.findfirstvisibleitemposition()!=0){//如果刷新完毕的时候用户没有注视header mheaderview.settopmargin(-mheaderview.getrealheight()); return; } if(timer!=null)timer.cancel(); final timertask timertask = new timertask() { @override public void run() { if(mheaderview==null)return; // log.i("alex2","topmargin是"+mheaderview.gettopmargin()+" height是"+mheaderview.getheight()); if(mheaderview.gettopmargin()>-mheaderview.getrealheight()){//如果header没有完全缩回去 handler.post(new runnable() { @override public void run() { if (misheaderready || misrefreshing) {//如果目前是ready状态或者正在刷新状态 // log.i("alex2", "现在是ready状态"); int delta = mheaderview.gettopmargin() / 9; if (delta < 5) delta = 5; if (mheaderview.gettopmargin() > 0) mheaderview.settopmargin(mheaderview.gettopmargin() - delta); } else {//如果是普通状态 // log.i("alex2", "现在是普通状态"); mheaderview.settopmargin(mheaderview.gettopmargin() - 5); } } }); } else if(timer!=null){//如果已经完全缩回去了,但是动画还没有结束,就结束掉动画 timer.cancel(); handler.post(new runnable() { @override public void run() { mheaderview.setstate(mheaderview.state_finish); } }); } } }; timer = new timer(); timer.scheduleatfixedrate(timertask,0,10); } /** * 头部是通过ontouchevent控制的 * @param event * @return */ @override public boolean ontouchevent(motionevent event) { switch (event.getaction()) { case motionevent.action_move: int delta = (int)(event.gety()-oldy); oldy = event.gety(); if (layoutmanager.findviewbyposition(0) instanceof customdragheaderview) { isheader = true; updateheaderheight(delta);//更新margin高度 }else{ isheader = false; if(mheaderview!=null && !misrefreshing)mheaderview.settopmargin(-mheaderview.getrealheight()); } break; // case motionevent.action_down: // log.i("alex", "touch down"); // oldy = event.gety(); // if(timer!=null)timer.cancel(); // break; case motionevent.action_up: // log.i("alex", "抬手啦!!!! touch up "); if(misheaderready && !misrefreshing)startrefresh(); if(isheader)resetheaderheight();//抬手之后恢复高度 break; case motionevent.action_cancel: // log.i("alex", "touch cancel"); break; } return super.ontouchevent(event); } /** * 因为设置了子元素的onclicklistener之后,ontouch方法的down失效,所以要在分发前获取手指的位置 * @param ev * @return */ @override public boolean dispatchtouchevent(motionevent ev) { // todo auto-generated method stub switch (ev.getaction()) { case motionevent.action_down: // log.i("alex", "touch down分发前"); oldy = ev.gety(); if (timer != null) timer.cancel(); break; } return super.dispatchtouchevent(ev); } public void setonrefreshlistener(onrefreshlistener listener){ this.refreshlistener = listener; } /** * 设置是否支持下啦刷新的功能 * * @param enable */ public void setpullrefreshenable(boolean enable) { misrefreshing = false; menablepullrefresh = enable; if(mheaderview==null)return; if (!menablepullrefresh) { mheaderview.setonclicklistener(null); } else { mheaderview.setstate(customdragfooterview.state_normal); mheaderview.setvisibility(visible); } } /** * 停止下拉刷新,并且通过动画让头部自己缩回去 */ public void stoprefresh() { if (misrefreshing == true) { misrefreshing = false; misheaderready = false; if(mheaderview==null)return; mheaderview.setstate(customdragfooterview.state_normal); resetheaderheight(); } } /** * 在用户没有用手控制的情况下,通过动画把头部露出来并且执行刷新 */ public void forcerefresh(){ if(mheaderview==null)mheaderview = (customdragheaderview) layoutmanager.findviewbyposition(0); if(mheaderview!=null)mheaderview.setstate(customdragheaderview.state_refreshing); misrefreshing = true; log.i("alex2", "现在开始强制刷新"); misheaderready = false; smoothshowheader(); if (refreshlistener != null)refreshlistener.onrefresh(); } private void startrefresh() { misrefreshing = true; mheaderview.setstate(customdragheaderview.state_refreshing); log.i("alex2", "现在开始加载"); misheaderready = false; if (refreshlistener != null) refreshlistener.onrefresh(); } public interface onrefreshlistener{ public void onrefresh(); } /** * 适用于本recycler的头部下拉刷新view */ public static class customdragheaderview extends linearlayout { public final static int state_normal = 0; public final static int state_ready = 1; public final static int state_refreshing = 2; public final static int state_finish = 3; public float screendensity; private final int rotate_anim_duration = 180; private context mcontext; private view mcontentview; private view mprogressbar; private imageview marrowimageview; private textview mhinttextview; private animation mrotateupanim; private animation mrotatedownanim; public customdragheaderview(context context) { super(context); initview(context); } public customdragheaderview(context context, attributeset attrs) { super(context, attrs); initview(context); } private int mstate; public void setstate(int state) { if (state == mstate) return; if (state == state_refreshing) { // 显示进度 marrowimageview.clearanimation(); marrowimageview.setvisibility(view.invisible); mprogressbar.setvisibility(view.visible); } else { // 显示箭头图片 marrowimageview.setvisibility(view.visible); mprogressbar.setvisibility(view.invisible); } switch (state) { case state_normal: if (mstate == state_ready) { marrowimageview.startanimation(mrotatedownanim); mhinttextview.settext(r.string.xlistview_header_hint_normal); } else if (mstate == state_refreshing) {//如果是从刷新状态过来 // marrowimageview.clearanimation(); marrowimageview.setvisibility(invisible); mhinttextview.settext("load completed"); } break; case state_ready: if (mstate != state_ready) { marrowimageview.clearanimation(); marrowimageview.startanimation(mrotateupanim); } mhinttextview.settext(r.string.xlistview_header_hint_ready); break; case state_refreshing: mhinttextview.settext(r.string.xlistview_header_hint_loading); break; case state_finish: marrowimageview.setvisibility(view.visible); mhinttextview.settext(r.string.xlistview_header_hint_normal); break; default: } mstate = state; } public void settopmargin(int height) { if (mcontentview==null) return ; layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); lp.topmargin = height; mcontentview.setlayoutparams(lp); } // public int gettopmargin() { layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); return lp.topmargin; } public void setheight(int height){ if (mcontentview==null) return ; layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); lp.height = height; mcontentview.setlayoutparams(lp); } private int realheight; /** * 得到这个headerview真实的高度,而且这个高度是自己定的 * @return */ public int getrealheight(){ return realheight; } private void initview(context context) { mcontext = context; this.setlayoutparams(new layoutparams(layoutparams.match_parent, layoutparams.wrap_content));//recyclerview里不加这句话的话宽度就会比较窄 linearlayout moreview = (linearlayout) layoutinflater.from(mcontext).inflate(r.layout.xlistview_header, null); addview(moreview); moreview.setlayoutparams(new layoutparams(layoutparams.match_parent, layoutparams.wrap_content)); mcontentview = moreview.findviewbyid(r.id.xlistview_header_content); layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); log.i("alex", "初始height是" + mcontentview.getheight()); lp.height = 150;//手动设置高度,如果要手动加载更多的时候才设置 screendensity = getcontext().getresources().getdisplaymetrics().density;//设置屏幕密度,用来px向dp转化 lp.height = dp2px(screendensity,header_height);//头部高度75dp realheight = lp.height; lp.topmargin = -lp.height; mcontentview.setlayoutparams(lp); marrowimageview = (imageview) findviewbyid(r.id.xlistview_header_arrow); mhinttextview = (textview) findviewbyid(r.id.xlistview_header_hint_textview); mhinttextview.setpadding(0,dp2px(screendensity,3),0,0);//不知道为什么这个文字总会向上偏一下,所以要补回来 mprogressbar = findviewbyid(r.id.xlistview_header_progressbar); mrotateupanim = new rotateanimation(0.0f, -180.0f, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); mrotateupanim.setduration(rotate_anim_duration); mrotateupanim.setfillafter(true); mrotatedownanim = new rotateanimation(-180.0f, 0.0f, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); mrotatedownanim.setduration(rotate_anim_duration); mrotatedownanim.setfillafter(true); } } public static int dp2px(float density, int dp) { if (dp == 0) { return 0; } return (int) (dp * density + 0.5f); } public static class customdragrecyclerfooterview extends linearlayout { public final static int state_normal = 0; public final static int state_ready = 1; public final static int state_loading = 2; public final static int state_error = 3; private context mcontext; private view mcontentview; private view mprogressbar; private textview mhintview; public customdragrecyclerfooterview(context context) { super(context); initview(context); } public customdragrecyclerfooterview(context context, attributeset attrs) { super(context, attrs); initview(context); } public void setstate(int state) { mprogressbar.setvisibility(view.invisible); // mhintview.setvisibility(view.invisible); if (state == state_ready) { mhintview.setvisibility(view.visible); mhintview.settext("松手加载更多"); } else if (state == state_loading) { mprogressbar.setvisibility(view.visible); mhintview.setvisibility(invisible); } else if(state == state_error){ mprogressbar.setvisibility(gone); mhintview.setvisibility(visible); mhintview.settext(r.string.xlistview_footer_hint_ready); } else { mhintview.setvisibility(view.visible); mhintview.settext(r.string.xlistview_footer_hint_normal); mhintview.settext("load more"); } } public void setbottommargin(int height) { if (height < 0) return ; layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); lp.bottommargin = height; mcontentview.setlayoutparams(lp); } public int getbottommargin() { layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); return lp.bottommargin; } /** * normal status */ public void normal() { mhintview.setvisibility(view.visible); mprogressbar.setvisibility(view.gone); } /** * loading status */ public void loading() { mhintview.setvisibility(view.gone); mprogressbar.setvisibility(view.visible); } /** * hide footer when disable pull load more */ public void hide() { layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); lp.height = 1;//这里如果设为0那么layoutmanger就会抓不到 mcontentview.setlayoutparams(lp); mcontentview.setbackgroundcolor(color.black);//这里的颜色要和自己的背景色一致 } /** * show footer */ public void show() { layoutparams lp = (layoutparams)mcontentview.getlayoutparams(); lp.height = layoutparams.wrap_content; lp.width = layoutparams.match_parent; mcontentview.setlayoutparams(lp); mcontentview.setbackgroundcolor(color.white);//这里的颜色要和自己的背景色一致 } private void initview(context context) { mcontext = context; this.setlayoutparams(new layoutparams(layoutparams.match_parent, layoutparams.wrap_content)); linearlayout moreview = (linearlayout) layoutinflater.from(mcontext).inflate(r.layout.layout_customdragfooterview, null); addview(moreview); moreview.setlayoutparams(new layoutparams(layoutparams.match_parent, layoutparams.wrap_content)); mcontentview = moreview.findviewbyid(r.id.rlcontentview); mprogressbar = moreview.findviewbyid(r.id.pbcontentview); mhintview = (textview)moreview.findviewbyid(r.id.ctvcontentview); mhintview.settext("load more"); // mprogressbar.setvisibility(visible);//一直会显示转圈,自动加载更多时使用 } } /** * 为了防止代码上的混乱,使用这个recyclerview自己内置的一个adapter * @param <t> */ public static abstract class alxdragrecyclerviewadapter<t> extends recyclerview.adapter<recyclerview.viewholder>{ protected static final int type_header = 436874; protected static final int type_item = 256478; protected static final int type_footer = 9621147; private int item; private viewholder vhitem; protected boolean loadmore; private list<t> datalist; public list<t> getdatalist() { return datalist; } public void setdatalist(list<t> datalist) { this.datalist = datalist; } public alxdragrecyclerviewadapter(list<t> datalist,int itemlayout,boolean pullenable){ this.datalist = datalist; this.item = itemlayout; this.loadmore = pullenable; } public abstract viewholder setitemviewholder(view itemview); private t getobject(int position){ if(datalist!=null && datalist.size()>=position)return datalist.get(position-1);//如果有header return null; } @override public recyclerview.viewholder oncreateviewholder(viewgroup parent, int viewtype) { if (viewtype == type_item) { //inflate your layout and pass it to view holder view itemview = layoutinflater.from(parent.getcontext()).inflate(item,null); log.i("alex","itemview是"+itemview); this.vhitem = setitemviewholder(itemview); log.i("alex","vhitem是"+vhitem); return vhitem; } else if (viewtype == type_header) { //inflate your layout and pass it to view holder view headerview = new customdragheaderview(parent.getcontext()); return new vhheader(headerview); } else if(viewtype==type_footer){ customdragrecyclerfooterview footerview = new customdragrecyclerfooterview(parent.getcontext()); return new vhfooter(footerview); } throw new runtimeexception("there is no type that matches the type " + viewtype + " + make sure your using types correctly"); } public void setpullloadmoreenable(boolean enable){ this.loadmore = enable; } public boolean getpullloadmoreenable(){return loadmore;} @override public void onbindviewholder(recyclerview.viewholder holder, int position) {//相当于getview log.i("alex","正在绑定"+position+" "+holder.getclass()); if (vhitem!=null && holder.getclass() == vhitem.getclass()) { //cast holder to vhitem and set data inititemview(holder,position,getobject(position)); }else if (holder instanceof alxdragrecyclerviewadapter.vhheader) { //cast holder to vhheader and set data for header. }else if(holder instanceof alxdragrecyclerviewadapter.vhfooter){ if(!loadmore)((vhfooter)holder).footerview.hide();//第一次初始化显示的时候要不要显示footerview } } @override public int getitemcount() { return (datalist==null ||datalist.size()==0)?1:datalist.size() + 2;//如果有header,若list不存在或大小为0就没有footview,反之则有 }//这里要考虑到头尾部,多以要加2 /** * 根据位置判断这里该用哪个viewholder * @param position * @return */ @override public int getitemviewtype(int position) { if (position == 0)return type_header; else if(ispositonfooter(position))return type_footer; return type_item; } protected boolean ispositonfooter(int position){//这里的position从0算起 if (datalist == null && position == 1) return true;//如果没有item return position == datalist.size() + 1;//如果有item(也许为0) } // class vhitem extends recyclerview.viewholder { // public vhitem(view itemview) { // super(itemview); // } // public view getitemview(){return itemview;} // } // protected class vhheader extends recyclerview.viewholder { public vhheader(view headerview) { super(headerview); } } protected class vhfooter extends recyclerview.viewholder { public customdragrecyclerfooterview footerview; public vhfooter(view itemview) { super(itemview); footerview = (customdragrecyclerfooterview)itemview; } } public abstract void inititemview(viewholder itemholder,int posion,t entity); } }