Android自定义控件实现下拉刷新效果
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。先这样吧。像上拉加载更多,我感觉也可以这么实现。有时间试试吧,大家有时间也可以动动手试试。
好吧。大致就这些,有疑问或建议请留言,共同进步,谢谢!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。