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

Android控件PullRefreshViewGroup实现下拉刷新和上拉加载

程序员文章站 2023-12-02 23:58:40
本文实例为大家分享了android实现下拉刷新和上拉加载更多的具体代码,供大家参考,具体内容如下 先分享下源码:android实现下拉刷新和上拉加载更多 实现思路:由p...

本文实例为大家分享了android实现下拉刷新和上拉加载更多的具体代码,供大家参考,具体内容如下

先分享下源码:android实现下拉刷新和上拉加载更多

实现思路:由pullrefreshviewgroup控件来接管标准控件(比如recyclerview、listview等)的滑动,调用标准控件的内部方法进行短距离滑动,不再由标准控件自己来处理事件,而完全由pullrefreshviewgroup控件来处理触摸事件。标准控件内部的滑动距离等属性,通过反射获得computeverticalscrollextent、computeverticalscrollrange、computeverticalscrolloffset这三个方法来获得。

pullrefreshviewgroup控件的布局如下 

Android控件PullRefreshViewGroup实现下拉刷新和上拉加载

部分代码实现

触摸滑动事件处理

@override 
 public boolean onintercepttouchevent(motionevent ev) { 
  boolean bret = false; 
  switch (ev.getaction()) { 
   case motionevent.action_down: { 
    mprey = ev.gety(); 
    log.d(tag, "mprey:" + string.valueof(mprey)); 
   } 
   break; 
   case motionevent.action_move: { 
    float cury = ev.gety(); 
    float distance = cury - mprey; 
    if (math.abs(distance) >= mtouchslop) { 
     msliding = bret = true; 
 
     //修正第一次滑动的卡顿 
     if (distance > 0) { 
      mprey += mtouchslop; 
     } else { 
      mprey -= mtouchslop; 
     } 
 
     if (!mscroller.isfinished()) { 
      mscroller.abortanimation(); 
     } 
    } else { 
     msliding = bret = false; 
    } 
   } 
   break; 
   case motionevent.action_up: 
   case motionevent.action_cancel: { 
    bret = msliding; 
   } 
   break; 
  } 
  return bret ? true : super.onintercepttouchevent(ev); 
 } 
 
 @override 
 public boolean ontouchevent(motionevent event) { 
  boolean bret = false; 
 
  vtracker.addmovement(event); 
 
  switch (event.getaction()) { 
   case motionevent.action_down: { 
    mprey = event.gety(); 
    bret = true; 
   } 
   break; 
   case motionevent.action_move: { 
    float cury = event.gety(); 
    float distance = cury - mprey; 
    log.d(tag, "mprey:" + string.valueof(mprey) + " distance:" + string.valueof(distance)); 
    if (distance != 0) { 
     bret = true; 
 
     if (msrcheighthead == -1 && mhaspullrefresh) { 
      view child0view = mheadview; 
      msrcheighthead = child0view.getheight(); 
     } 
 
     scrollby(distance); 
    } 
 
    mprey = cury; 
   } 
   break; 
   case motionevent.action_up: 
   case motionevent.action_cancel: { 
    mprecury = 0; 
 
    view child0view = mheadview; 
    int child0height = null != child0view ? child0view.getheight() : 0; 
    int child0height2 = null != child0view ? child0view.getlayoutparams().height : 0; //视图的最终高度是有这个来决定的,请看onmeasure 函数的实现 
    // int child0height3 = child0view.getmeasuredheight(); 
    if (child0height2 != child0height) { 
     child0height = child0height2; 
    } 
    int child0top = null != child0view ? child0view.gettop() : 0; 
    int dy = child0height - msrcheighthead + (msrcheighthead - math.abs(child0top)); 
    log.d(tag, "ontouchevent()action_up child0height:" + string.valueof(child0height) + " msrcheighthead:" + string.valueof(msrcheighthead) + " child0top:" + string.valueof(child0top)); 
    if (dy > 0) {//恢复拉伸视图的位置 
     if (!mloadingmore && dy > mcanrefreshheight && child0top + child0height2 > mcanrefreshheight && mrefreshload != null) { 
      dy -= mcanrefreshheight; 
 
      if (!mpullrefreshloading) { 
       mpullrefreshloading = true; 
       mtvrefreshinfo.settext("正在加载..."); 
       mrefreshload.pullrefreshstartload(); 
      } 
     } 
     mscroller.startscroll(0, 0, 0, -dy); 
     invalidate(); 
    } else { 
     vtracker.computecurrentvelocity(1000); 
 
     float yvel = vtracker.getyvelocity(); 
     if (yvel != 0) {//为了满足内部视图的快速滚动( 中间内容视图 ) 
      mscroller.fling(0, 0, 0, (int) yvel, 0, 0, integer.min_value, integer.max_value); 
      invalidate(); 
     } 
    } 
 
    vtracker.clear(); 
    bret = true; 
   } 
   break; 
  } 
  return bret ? true : super.ontouchevent(event); 
 } 

小距离滑动代码

private void scrollby(float distance) { 
  view child0view = mheadview; 
  view child1view = getchildat(null == mheadview ? 0 : 1); 
  float distanceremain = 0; 
 
  int child0top = null != child0view ? child0view.gettop() : 0; 
  // int child0height = child0view.getheight(); 
 
  if (distance < 0) {//向上 
   int child1top = child1view.gettop(); 
   // int child1height = child1view.getheight(); 
 
   //child0view 缩小 
   if (-1 != msrcheighthead && null != child0view && child0view.getheight() > msrcheighthead) { 
    float off = distance; 
    if (child0view.getheight() + distance < msrcheighthead) { 
     off = -(child0view.getheight() - msrcheighthead); 
     distance -= off; 
    } else { 
     distance = 0; 
    } 
 
    child0view.getlayoutparams().height += (int) off; 
    child1top += (int) off; //child0view 缩小的同时, child1view 的高度也会随之上升 这里很重要 
    requestlayout(); 
    child1view.offsettopandbottom((int) off); 
    if (null != mtailview) { 
     mtailview.offsettopandbottom((int) off); 
    } 
   } 
 
   if (distance != 0) { 
    if (child0top + msrcheighthead + distance <= 0) { 
     distanceremain = -(distance + (child0top + msrcheighthead));//正数 
     distance = -(child0top + msrcheighthead);//负数 
    } 
 
    //可以显示加载更多吗? 
    boolean bdirectdown = false; 
    boolean bcanscroll = child1view.canscrollvertically(1) || child1view.canscrollvertically(-1); 
    if (!bcanscroll) { 
     int child1childcount = 0; 
     if (child1view instanceof viewgroup) { 
      child1childcount = ((viewgroup) child1view).getchildcount(); 
     } 
     if (child1childcount > 0) { 
      viewgroup viewgroupchild1 = (viewgroup) child1view; 
 
      view child1lastitem = viewgroupchild1.getchildat(child1childcount - 1); 
      int child1viewbottom = viewgroupchild1.getbottom(); 
      int child1lastitembottom = child1lastitem.getbottom() + child1top; //相对于 imagescaleviewgroup 的位置 
      //增加 child1viewbottom > getheight() 来控制 scrollview 
      if (child1lastitembottom == getheight()) { 
       bdirectdown = true; 
      } 
     } 
    } 
    //正在下拉刷新的时候,不能显示加载更多 
    if ((bcanscroll || bdirectdown) && null != mtailview && !mpullrefreshloading) { 
 
     int nverticalscrollextent = 0, nverticalscrollrange = 0, nverticalscrolloffset = 0; 
     class c = null; 
 
     try { 
      c = class.forname(child1view.getclass().getname()); 
     } catch (exception ex) { 
 
     } 
     try { 
      if (null == mcomputeverticalscrollextent) { 
       method computeverticalscrollextent = findcomputeverticalmethod(c, "computeverticalscrollextent"); 
       computeverticalscrollextent.setaccessible(true); 
       mcomputeverticalscrollextent = computeverticalscrollextent; 
      } 
      nverticalscrollextent = (int) mcomputeverticalscrollextent.invoke(child1view); 
     } catch (exception ex) { 
 
     } 
     try { 
      if (null == mcomputeverticalscrollrange) { 
       method computeverticalscrollrange = findcomputeverticalmethod(c, "computeverticalscrollrange"); 
       computeverticalscrollrange.setaccessible(true); 
       mcomputeverticalscrollrange = computeverticalscrollrange; 
      } 
 
      nverticalscrollrange = (int) mcomputeverticalscrollrange.invoke(child1view); 
     } catch (exception ex) { 
 
     } 
     try { 
      if (null == mcomputeverticalscrolloffset) { 
       method computeverticalscrolloffset = findcomputeverticalmethod(c, "computeverticalscrolloffset"); 
       computeverticalscrolloffset.setaccessible(true); 
       mcomputeverticalscrolloffset = computeverticalscrolloffset; 
      } 
      nverticalscrolloffset = (int) mcomputeverticalscrolloffset.invoke(child1view); 
     } catch (exception ex) { 
 
     } 
 
 
     int range = nverticalscrollrange - nverticalscrollextent; 
     if (nverticalscrolloffset + distanceremain > range) { 
      float noff = distanceremain - (range - nverticalscrolloffset); 
 
      distanceremain = range - nverticalscrolloffset; 
      distance -= noff; 
     } 
 
     int child3bottom = mtailview.getbottom(); 
 
     if (child3bottom + distance < getheight()) { 
      distance = getheight() - child3bottom; 
     } 
    } 
 
    if (!bcanscroll) { 
     distanceremain = 0; 
    } 
   } 
 
  } else {//向下 
   int nscrolloffset = 0; 
   try { 
    class c = class.forname(child1view.getclass().getname()); 
    method computeverticalscrolloffset = findcomputeverticalmethod(c, "computeverticalscrolloffset");//c.getdeclaredmethod("computeverticalscrolloffset"); 
    computeverticalscrolloffset.setaccessible(true); 
    nscrolloffset = (int) computeverticalscrolloffset.invoke(child1view); 
   } catch (exception ex) { 
 
   } 
 
   int child2top = null != mtailview ? mtailview.gettop() : getheight();//注意默认值 
   if (child2top < getheight()) { 
    if (child2top + distance > getheight()) { 
     distanceremain = distance - (getheight() - child2top); 
     distance = getheight() - child2top; 
    } 
   } else if (nscrolloffset > 0) {//内部有滚动,那么就要计算内部滚动距离,其他分配给整体滚动 
    if (nscrolloffset - distance <= 0) { 
     distanceremain = -nscrolloffset; 
     // distance = distance - nscrolloffset; 
     distance = 0; //内部能滚动,不让外部去滚动 
     if (!mscroller.isfinished()) { 
      mscroller.abortanimation(); //内部滚动完后,立即停止 
     } 
    } else { 
     distanceremain = -distance;//负数 
     distance = 0; 
    } 
   } else { 
    if (child0top + distance > 0) {//child0放大,child1移动 
     int off = (int) (child0top + distance); 
     distance = -child0top; 
 
     if (null != child0view) { 
      child0view.getlayoutparams().height += off; 
      requestlayout(); 
     } else { 
      off = 0; 
     } 
 
     child1view.offsettopandbottom(off); 
     if (null != mtailview) { 
      mtailview.offsettopandbottom(off); 
     } 
    } 
   } 
  } 
 
  if (0 != (int) distance) { 
   if (null != child0view) { 
    child0view.offsettopandbottom((int) distance); 
   } 
   child1view.offsettopandbottom((int) distance); 
   if (null != mtailview) { 
    mtailview.offsettopandbottom((int) distance); 
   } 
 
   requestlayout();//奇酷360这里必须调用, 否则显示有点问题 
  } 
 
  scrollbyformidview(distanceremain);//外部无法滚动的时候,内部滚动 
 
  if (!mpullrefreshloading && !mloadingmore) { 
   int tailviewtop = null != mtailview ? mtailview.gettop() : getheight();//注意默认值 
 
   if (tailviewtop < getheight() && mhasloadmore) {//加载更多 
    mloadingmore = true; 
    if (mrefreshload != null) { 
     mrefreshload.pullupstartloadmore(); 
    } 
   } else { 
    if (mhaspullrefresh) { 
     if (distance < 0) { 
      int child0bottom = child0view.getbottom(); 
      if (child0bottom < mcanrefreshheight) { 
       mtvrefreshinfo.settext("下拉刷新"); 
      } 
     } else { 
      int child0bottom = child0view.getbottom(); 
      if (child0bottom > mcanrefreshheight) { 
       mtvrefreshinfo.settext("松开刷新"); 
      } 
     } 
    } 
   } 
  } 
 } 

处理标准控件小距离滚动代码,这里listview有点特殊。

private void scrollbyformidview(float distanceremain) { 
  if (0 != (int) distanceremain) { 
   view child1view = getchildat(null == mheadview ? 0 : 1); 
   if (child1view instanceof listview) { 
    ((listview) child1view).smoothscrollby((int) distanceremain, 0); 
   } /*else if (child1view instanceof scrollview){ 
    ((scrollview) child1view).smoothscrollby(0,(int) distanceremain); 
   }*/ else { 
    child1view.scrollby(0, (int) distanceremain); 
   } 
  } 
 } 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。