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

Android仿XListView支持下拉刷新和上划加载更多的自定义RecyclerView

程序员文章站 2024-03-31 16:31:52
首先给大家展示下效果图,感觉还不错,请继续往下阅读: 下拉刷新:        上划加载   &nbs...

首先给大家展示下效果图,感觉还不错,请继续往下阅读:

下拉刷新:

Android仿XListView支持下拉刷新和上划加载更多的自定义RecyclerView      Android仿XListView支持下拉刷新和上划加载更多的自定义RecyclerView

Android仿XListView支持下拉刷新和上划加载更多的自定义RecyclerView

上划加载

Android仿XListView支持下拉刷新和上划加载更多的自定义RecyclerView      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);
 }
}