当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义控件实现下拉刷新效果

Android自定义控件实现下拉刷新效果

2019年07月24日  | 移动技术网移动技术  | 我要评论

app开发中下拉刷新是最常接触到的一个功能,也有很多开源的框架,封装的非常棒。前段时间了解了一下viewdraghelper,遂用它实现了下拉刷新的功能。

大概和我之前的viewdraghelper之拖动加载(类似淘宝)这篇代码类似。只是做了相关改动。具体的可以看一下那篇博文了解一下用到的viewdraghelper的一些知识点。该界面主要是一个linearlayout,上面的下拉刷新是一个textview(用tv代替),当然这个可以定制,在此只是用一个textview代替,实现简单的功能,下面是一个listview(用lv代替),当然listview也是可以定制的,可以使gridview或者其他你想要的都可以,在此也是只用listview代替。大概的讲讲吧:

首先,在onlayout中将tv置于屏幕上方,将lv充满屏幕;

上图中蓝色部分是整个手机的屏幕,红色部分是下拉提示tv。tv是置于屏幕之外的是不显示的。

@override 
 protected void onlayout(boolean changed, int l, int t, int r, int b) { 
  if (pulltext.gettop() == 0) { 
   viewheight = pulltext.getmeasuredheight(); 
   pulltext.layout(l, 0, r, b); 
   mylist.layout(l, 0, r, b); 
   pulltext.offsettopandbottom(-viewheight); 
  } else { 
   pulltext.layout(l, pulltext.gettop(), r, pulltext.getbottom()); 
   mylist.layout(l, mylist.gettop(), r, mylist.getbottom()); 
  } 
 } 

 上面的代码段中,pulltext即是tv,mylist是lv。这样在下拉lv的时候,tv就会跟着往下走,所以就会出现在屏幕中实现我们想要的效果。

 /** 
  * 这是拖拽效果的主要逻辑 
  */ 
 private class draghelpercallback extends viewdraghelper.callback { 
 
  @override 
  public void onviewpositionchanged(view changedview, int left, int top, 
    int dx, int dy) { 
   int childindex = 1; 
   if (changedview == mylist) { 
    childindex = 2; 
   } 
   onviewposchanged(childindex, top); 
  } 
 
  @override 
  public boolean trycaptureview(view child, int pointerid) { 
   return true; 
  } 
 
  @override 
  public int getviewverticaldragrange(view child) { 
   return 1; 
  } 
 
  @override 
  public void onviewreleased(view releasedchild, float xvel, float yvel) { 
   refreshornot(releasedchild, yvel); 
  } 
 
  @override 
  public int clampviewpositionvertical(view child, int top, int dy) { 
   int finaltop = top; 
   if (child == pulltext) { 
    if (top > 0) { 
     finaltop = 0; 
    } 
   } else if (child == mylist) { 
    if (top < 0) { 
     finaltop = 0; 
    } 
    if(top >= viewheight){ 
     pulltext.settext("松开刷新"); 
    }else{ 
     pulltext.settext("下拉刷新"); 
    } 
   } 
   return child.gettop() + (finaltop - child.gettop()) / 2; 
  } 
 }

上面的代码段中,主要是在clampviewpositionvertical中判断滑动的位置,作用的子view。其他就不多说了,大致和之前的博客相同。主要说说onviewreleased吧。在此函数中是在用户手势抬起时响应的,所以我们在此实现下拉后的刷新。我们先定义一个接口,以便在刷新的时候调用。

public interface pulltorefreshnotifier { 
  public void onpull(); 
 } 
public void setpulltorefreshnotifier(pulltorefreshnotifier pullnotifier) { 
  this.pullnotifier = pullnotifier; 
 } 
private void refreshornot(view releasedchild, float yvel) { 
  int finaltop = 0; 
  if (releasedchild == pulltext) { 
   // 拖动第一个view松手 
   if (yvel < -50) { 
    finaltop = 0; 
   } else { 
    finaltop = viewheight; 
   } 
  } else { 
   // 拖动第二个view松手 
   if (yvel > viewheight - 5 || releasedchild.gettop() >= viewheight) { 
    finaltop = viewheight; 
    if (null != pullnotifier) { 
     pullnotifier.onpull(); 
    } 
    pulltext.settext("正在刷新"); 
   } 
  } 
 
  if (vdh.smoothslideviewto(mylist, 0, finaltop)) { 
   viewcompat.postinvalidateonanimation(this); 
  } 
 } 

拖动第二个view时,也就是lv时,我们判断一下是否需要刷新,需要刷新则执行onpull();
然后我们来看一下主要的activity:

package com.maxi.pulltorefreshtest; 
 
import android.annotation.suppresslint; 
import android.app.activity; 
import android.os.bundle; 
import android.os.handler; 
import android.os.message; 
 
import com.maxi.pulltorefreshtest.adapter.projectadapter; 
import com.maxi.pulltorefreshtest.widget.mylistview; 
import com.maxi.pulltorefreshtest.widget.pulltorefreshgroup; 
import com.maxi.pulltorefreshtest.widget.pulltorefreshgroup.pulltorefreshnotifier; 
 
public class mainactivity extends activity { 
 private pulltorefreshgroup pulllistgroup; 
 private boolean isdown = false; 
 private mylistview mylist; 
 private projectadapter pa; 
 @override 
 protected void oncreate(bundle savedinstancestate) { 
  super.oncreate(savedinstancestate); 
  setcontentview(r.layout.activity_main); 
  findview(); 
  init(); 
 } 
 
 private void findview() { 
  pulllistgroup = (pulltorefreshgroup) findviewbyid(r.id.pulltorefresh); 
  mylist = pulllistgroup.returnmylist(); 
 } 
 
 private void init() { 
  pulltorefreshnotifier pullnotifier = new pulltorefreshnotifier() { 
   @override 
   public void onpull() { 
    // todo auto-generated method stub 
    download(); 
   } 
  }; 
  pulllistgroup.setpulltorefreshnotifier(pullnotifier); 
  pa = new projectadapter(this); 
  mylist.setadapter(pa); 
  pa.notifydatasetchanged(); 
 } 
 
 private void download() { 
  if (!isdown) { 
   isdown = true; 
   new thread(new runnable() { 
 
    @override 
    public void run() { 
     // todo auto-generated method stub 
     try { 
      thread.sleep(2000); 
      handler.sendemptymessage(1); 
     } catch (interruptedexception e) { 
//      todo auto-generated catch block 
      e.printstacktrace(); 
     } 
    } 
   }).start(); 
  } 
 } 
 
 @suppresslint("handlerleak") 
 private handler handler = new handler() { 
 
  @override 
  public void handlemessage(message msg) { 
   // todo auto-generated method stub 
   super.handlemessage(msg); 
   switch (msg.what) { 
   case 1: 
    pulllistgroup.refreshcomplete(); 
    isdown = false; 
    break; 
   default: 
    break; 
   } 
  } 
 
 }; 
} 

我们在他刷新的时候执行download();刷新数据。为了达到效果可以看出我让线程暂停2s。然后调用refreshcomplete();

public void refreshcomplete() { 
 if (vdh.smoothslideviewto(mylist, 0, 0)) { 
  viewcompat.postinvalidateonanimation(this); 
 } 
} 

实现刷新好后让tv继续返回屏幕上方。

上段代码中我们发现mylistview是重写的listview,主要是处理手势事件的。

package com.maxi.pulltorefreshtest.widget; 
 
import android.content.context; 
import android.util.attributeset; 
import android.view.motionevent; 
import android.view.view; 
import android.widget.listview; 
 
public class mylistview extends listview { 
 boolean allowdragbottom = true; 
 float downy = 0; 
 boolean needconsumetouch = true; 
 public mylistview(context context){ 
  super(context); 
 } 
 public mylistview(context context, attributeset attrs) { 
  super(context, attrs); 
  // todo auto-generated constructor stub 
 } 
 
 @override 
 public boolean dispatchtouchevent(motionevent ev) { 
  if (ev.getaction() == motionevent.action_down) { 
   downy = ev.getrawy(); 
   needconsumetouch = true; 
   if (getmyscrolly() == 0) { 
    allowdragbottom = true; 
   } else { 
    allowdragbottom = false; 
   } 
  } else if (ev.getaction() == motionevent.action_move) { 
   if (!needconsumetouch) { 
    getparent().requestdisallowintercepttouchevent(false); 
    return false; 
   } else if (allowdragbottom) { 
    if (downy - ev.getrawy() < -2) { 
     needconsumetouch = false; 
     getparent().requestdisallowintercepttouchevent(false); 
     return false; 
    } 
   } 
  } 
  getparent().requestdisallowintercepttouchevent(needconsumetouch); 
  return super.dispatchtouchevent(ev); 
 } 
 
 public int getmyscrolly() { 
  view c = getchildat(0); 
  if (c == null) { 
   return 0; 
  } 
  int firstvisibleposition = getfirstvisibleposition(); 
  int top = c.gettop(); 
  return -top + firstvisibleposition * c.getheight(); 
 } 
} 

ok。先这样吧。像上拉加载更多,我感觉也可以这么实现。有时间试试吧,大家有时间也可以动动手试试。

好吧。大致就这些,有疑问或建议请留言,共同进步,谢谢!

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网