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

Android使用PullToRefresh完成ListView下拉刷新和左滑删除功能

程序员文章站 2024-03-02 12:13:52
listview下刷新刷功能相信从事android开发的猿友们并不陌生,包括现在google亲儿子swiperefreshlayout实现效果在一些app上也能看见(不过个...

listview下刷新刷功能相信从事android开发的猿友们并不陌生,包括现在google亲儿子swiperefreshlayout实现效果在一些app上也能看见(不过个人不喜欢官方的刷新效果)。本文就带领一些刚入门android的朋友或者一起爱分享的朋友来简单的实现listview的下拉刷新和左滑删除效果。

一、本文主要内容:

使用pulltorefresh完成listview下拉、上拉刷新;
扩展pulltorefresh完美的实现listview左滑删除效果; 注意:本文中的pulltorefresh并非完整的开源库,个人把一些不需要的和平时无相关的类已删除。看起来更加精简,更加容易理解。
附上pulltorefresh源码库下载地址:http://download.csdn.net/detail/jaynm/9670737

二、先看效果:

1.listview下拉刷新、上拉加载更多:

Android使用PullToRefresh完成ListView下拉刷新和左滑删除功能

2.listview下拉刷新、上拉加载更多、左滑删除:

Android使用PullToRefresh完成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下拉刷新和左滑删除功能,希望对大家有所帮助