Android使用PullToRefresh完成ListView下拉刷新和左滑删除功能
listview下刷新刷功能相信从事android开发的猿友们并不陌生,包括现在google亲儿子swiperefreshlayout实现效果在一些app上也能看见(不过个人不喜欢官方的刷新效果)。本文就带领一些刚入门android的朋友或者一起爱分享的朋友来简单的实现listview的下拉刷新和左滑删除效果。
一、本文主要内容:
使用pulltorefresh完成listview下拉、上拉刷新;
扩展pulltorefresh完美的实现listview左滑删除效果; 注意:本文中的pulltorefresh并非完整的开源库,个人把一些不需要的和平时无相关的类已删除。看起来更加精简,更加容易理解。
附上pulltorefresh源码库下载地址:http://download.csdn.net/detail/jaynm/9670737
二、先看效果:
1.listview下拉刷新、上拉加载更多:
2.listview下拉刷新、上拉加载更多、左滑删除:
三、实现代码:
1.实现listview下拉刷新:
至于pulltorefreshbase类,自己修改过源码,代码太长这里就不贴出来,自己可以下载demo自己仔细阅读,主要看如何应用到自己项目中:
* created by caobo on 2016/11/1 0001. * listview下拉刷新、上拉加载更多 */ public class listviewactivity extends activity implements pulltorefreshbase.onrefreshlistener<listview> { private pulltorefreshlistview refreshlistview; private listview mlistview; //添加数据list集合 //todo:这里使用了linkedlist方便demo中添加数据使用,实际项目中使用arraylist即可。 private linkedlist<string> pulldata; private listadapter adapter; //标记下拉index private int pulldownindex = 0; //标记上拉index private int pullupindex = 0; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_listview); pulldata = new linkedlist<>(); refreshlistview = (pulltorefreshlistview) findviewbyid(r.id.refreshlistview); refreshlistview.setpullloadenabled(false); refreshlistview.setscrollloadenabled(true); refreshlistview.setonrefreshlistener(this); mlistview = refreshlistview.getrefreshableview(); adapter = new listadapter(getdata()); mlistview.setadapter(adapter); refreshlistview.onrefreshcomplete(); } @override public void onpulldowntorefresh(pulltorefreshbase<listview> refreshview) { onpulldown(); } @override public void onpulluptorefresh(pulltorefreshbase<listview> refreshview) { onpullup(); } /** * 预加载初始化数据list * @return */ public list<string> getdata() { for (int i = 1; i <= 20; i++) { pulldata.add("默认listview数据" + i); } return pulldata; } /** * 下拉刷新添加数据到list集合 */ public void onpulldown() { pulldata.addfirst("下拉刷新数据" + pulldownindex); pulldownindex++; refreshlistview.onrefreshcomplete(); adapter.notifydatasetchanged(); } /** * 上拉加载添加数据到list集合 */ public void onpullup() { pulldata.addlast("上拉加载数据" + pullupindex); pullupindex++; refreshlistview.onrefreshcomplete(); adapter.notifydatasetchanged(); } public void onbackclick(view view){ finish(); } }
是不是以上操作还是很简单的就完成了listview下拉刷新,上拉加载更多。
xml布局文件也很简单,只需要引用pulltorefreshlistview的地址即可:
这样我们就完成了一个listview列表的下拉刷新和上拉加载更多,个人认为pulltorefresh这个库还是很强大的。
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.jaynm.pulltorefreshscrollviewdemo.refresh.pulltorefreshlistview android:background="#000" android:id="@+id/refreshlistview" android:layout_width="match_parent" android:layout_height="match_parent" android:cachecolorhint="@android:color/transparent" android:divider="@color/consumer_bg" android:dividerheight="1px" android:fadingedge="none" android:orientation="vertical" android:overscrollmode="never" android:requiresfadingedge="none"> </com.jaynm.pulltorefreshscrollviewdemo.refresh.pulltorefreshlistview> </linearlayout>
1.实现listview下拉刷新、左滑删除:
注意:
a.这里重写listview生成swipemenulistview,所以他仍然是listview列表控件;
b.既然需要左滑,必须要在ontouchevent()方法里面来判断手势滑动的操作;
c.需要考虑到下拉、上拉和左滑事件的冲突;
d.需要考虑左滑删除事件每次只能有一个item处于删除状态;
@override public boolean ontouchevent(motionevent ev) { if (ev.getaction() != motionevent.action_down && mtouchview == null) return super.ontouchevent(ev); int action = ev.getaction(); switch (action) { case motionevent.action_down: int oldpos = mtouchposition; mdownx = ev.getx(); mdowny = ev.gety(); mtouchstate = touch_state_none; mtouchposition = pointtoposition((int) ev.getx(), (int) ev.gety()); if (mtouchposition == oldpos && mtouchview != null && mtouchview.isopen()) { mtouchstate = touch_state_x; mtouchview.onswipe(ev); return true; } view view = getchildat(mtouchposition - getfirstvisibleposition()); if (mtouchview != null && mtouchview.isopen()) { mtouchview.smoothclosemenu(); mtouchview = null; // return super.ontouchevent(ev); // try to cancel the touch event motionevent cancelevent = motionevent.obtain(ev); cancelevent.setaction(motionevent.action_cancel); ontouchevent(cancelevent); if (monmenustatechangelistener != null) { monmenustatechangelistener.onmenuclose(oldpos); } return true; } if (view instanceof swipemenulayout) { mtouchview = (swipemenulayout) view; mtouchview.setswipedirection(mdirection); } if (mtouchview != null) { mtouchview.onswipe(ev); } break; case motionevent.action_move: //有些可能有header,要减去header再判断 mtouchposition = pointtoposition((int) ev.getx(), (int) ev.gety()) - getheaderviewscount(); //如果滑动了一下没完全展现,就收回去,这时候mtouchview已经赋值,再滑动另外一个不可以swip的view //会导致mtouchview swip 。 所以要用位置判断是否滑动的是一个view if (!mtouchview.getswipenable() || mtouchposition != mtouchview.getposition()) { break; } float dy = math.abs((ev.gety() - mdowny)); float dx = math.abs((ev.getx() - mdownx)); if (mtouchstate == touch_state_x) { if (mtouchview != null) { mtouchview.onswipe(ev); } getselector().setstate(new int[]{0}); ev.setaction(motionevent.action_cancel); super.ontouchevent(ev); return true; } else if (mtouchstate == touch_state_none) { if (math.abs(dy) > max_y) { mtouchstate = touch_state_y; } else if (dx > max_x) { mtouchstate = touch_state_x; if (monswipelistener != null) { monswipelistener.onswipestart(mtouchposition); } } } break; case motionevent.action_up: if (mtouchstate == touch_state_x) { if (mtouchview != null) { boolean isbeforeopen = mtouchview.isopen(); mtouchview.onswipe(ev); boolean isafteropen = mtouchview.isopen(); if (isbeforeopen != isafteropen && monmenustatechangelistener != null) { if (isafteropen) { monmenustatechangelistener.onmenuopen(mtouchposition); } else { monmenustatechangelistener.onmenuclose(mtouchposition); } } if (!isafteropen) { mtouchposition = -1; mtouchview = null; } } if (monswipelistener != null) { monswipelistener.onswipeend(mtouchposition); } ev.setaction(motionevent.action_cancel); super.ontouchevent(ev); return true; } break; } return super.ontouchevent(ev); }
monswipelistener.onswipestart(mtouchposition);用来记录当前手势状态为motionevent.action_move开始向左滑动时的标记,monswipelistener.onswipeend(mtouchposition);用来记录当前手势状态为motionevent.action_up结束向左滑动时的标记,主要用于在activity界面回调时获取当前操作状态,既然如此,我们就可以根据onswipestart()和onswipeend()这两个回调方法来解决上述的第三个问题(需要考虑到下拉、上拉和左滑事件的冲突)
// 操作listview左滑时的手势操作,这里用于处理上下左右滑动冲突:开始滑动时则禁止下拉刷新和上拉加载手势操作,结束滑动后恢复上下拉操作 swipemenulistview.setonswipelistener(new swipemenulistview.onswipelistener() { @override public void onswipestart(int position) { refreshlistview.setpullrefreshenabled(false); } @override public void onswipeend(int position) { refreshlistview.setpullrefreshenabled(true); } });
refreshlistview.setpullrefreshenabled(false);方法便是我在pulltorefreshbase当中自定义的是否支持下拉刷新操作事件,我们可以根据onswipestart()和onswipeend()方法来进行设置。
这样我们就完美的解决了以上三点注意事项,从而实现listview左滑删除也是一件很easy的事情。
下面就看来上述注意事项d,这个需要在事件分发机制上下点功夫:因为当我们左滑出itema的删除按钮,再次去滑动itemb时,不能让它也出现,得要先关闭掉itema的删除状态,这样才是合理的操作,所以在方法中来处理拦截事件:
@ public boolean onintercepttouchevent(motionevent ev) { //在拦截处处理,在滑动设置了点击事件的地方也能swip,点击时又不能影响原来的点击事件 int action = ev.getaction(); switch (action) { case motionevent.action_down: mdownx = ev.getx(); mdowny = ev.gety(); boolean handled = super.onintercepttouchevent(ev); mtouchstate = touch_state_none; mtouchposition = pointtoposition((int) ev.getx(), (int) ev.gety()); view view = getchildat(mtouchposition - getfirstvisibleposition()); //只在空的时候赋值 以免每次触摸都赋值,会有多个open状态 if (view instanceof swipemenulayout) { //如果有打开了 就拦截. if (mtouchview != null && mtouchview.isopen() && !inrangeofview(mtouchview.getmenuview(), ev)) { return true; } mtouchview = (swipemenulayout) view; mtouchview.setswipedirection(mdirection); } //如果摸在另外个view if (mtouchview != null && mtouchview.isopen() && view != mtouchview) { handled = true; } if (mtouchview != null) { mtouchview.onswipe(ev); } return handled; case motionevent.action_move: float dy = math.abs((ev.gety() - mdowny)); float dx = math.abs((ev.getx() - mdownx)); if (math.abs(dy) > max_y || math.abs(dx) > max_x) { //每次拦截的down都把触摸状态设置成了touch_state_none 只有返回true才会走ontouchevent 所以写在这里就够了 if (mtouchstate == touch_state_none) { if (math.abs(dy) > max_y) { mtouchstate = touch_state_y; } else if (dx > max_x) { mtouchstate = touch_state_x; if (monswipelistener != null) { monswipelistener.onswipestart(mtouchposition); } } } return true; } } return super.onintercepttouchevent(ev); }
ok,以上便是swipemenulistview类中的所有事件处理代码,下面就可以activity中来引用我们所定义的swipemenulistview,从而实现listview下拉刷新,上拉加载,左滑删除效果。
// 创建左滑弹出的item swipemenucreator creator = new swipemenucreator() { @override public void create(swipemenu menu) { // 创建item swipemenuitem openitem = new swipemenuitem(getapplicationcontext()); // 设置item的背景颜色 openitem.setbackground(new colordrawable(color.red)); // 设置item的宽度 openitem.setwidth(utils.dip2px(swipelistviewactivity.this,90)); // 设置item标题 openitem.settitle("删除"); // 设置item字号 openitem.settitlesize(18); // 设置item字体颜色 openitem.settitlecolor(color.white); // 添加到listview的item布局当中 menu.addmenuitem(openitem); } }; // set creator swipemenulistview.setmenucreator(creator); // 操作删除按钮的点击事件 swipemenulistview.setonmenuitemclicklistener(new swipemenulistview.onmenuitemclicklistener() { @override public boolean onmenuitemclick(final int position, swipemenu menu, int index) { toast.maketext(swipelistviewactivity.this,"删除"+pulldata.get(position),toast.length_long).show(); return false; } }); // 操作listview左滑时的手势操作,这里用于处理上下左右滑动冲突:开始滑动时则禁止下拉刷新和上拉加载手势操作,结束滑动后恢复上下拉操作 swipemenulistview.setonswipelistener(new swipemenulistview.onswipelistener() { @override public void onswipestart(int position) { refreshlistview.setpullrefreshenabled(false); } @override public void onswipeend(int position) { refreshlistview.setpullrefreshenabled(true); } }); }
四、常用的一些属性介绍:
pull-to-refresh在xml中还能定义一些属性:
ptrrefreshableviewbackground 设置整个mpullrefreshlistview的背景色
ptrheaderbackground 设置下拉header或者上拉footer的背景色
ptrheadertextcolor 用于设置header与footer中文本的颜色
ptrheadersubtextcolor 用于设置header与footer中上次刷新时间的颜色
ptrshowindicator如果为true会在mpullrefreshlistview中出现icon,右上角和右下角,挺有意思的。
ptrheadertextappearance , ptrsubheadertextappearance分别设置拉header或者上拉footer中字体的类型颜色等等
ptrrotatedrawablewhilepulling当动画设置为rotate时,下拉是是否旋转。
总结:其实实现listview刷新并不困难,可能以前我们经常会看到有这样的组件存在:xlistview,这个组件应该在初学android的时候,很多人都见过,这就是很多人自己定义编写的listview下拉刷新,要实现功能也是没问题的,可是个人一直觉得效果体验程度太差。在项目中一直使用的是pulltorefresh下拉刷新。
好了,今天的分享就到这里了,写的不足的地方和不懂的地方大家可以留言共同探讨学习交流!
分享自己的it资源库qq群:459756676 主要是帮助it行业初学者分享视频学习资料,只要你是it爱好者都可进入共同学习!
以上所述是小编给大家介绍的android使用pulltorefresh完成listview下拉刷新和左滑删除功能,希望对大家有所帮助