Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多
最近做的类似于微博的项目中,有个android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多。
新浪微博就是使用这种方式的典型。
当用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容。这时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器对应的加载第n页就好了!!!)。通过分页分次加载数据,用户看多少就去加载多少。
通常这也分为两种方式,一种是设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。今天我就和大家分享一下滑动到底端时自动加载这个功能的实现。
效果图如下所示:
下拉刷新最主要的流程是:
(1). 下拉,显示提示头部界面(headerview),这个过程提示用户”下拉刷新”
(2). 下拉到一定程度,超出了刷新最基本的下拉界限,我们认为达到了刷新的条件,提示用户可以”松手刷新”了,效果上允许用户继续下拉
(3). 用户松手,可能用户下拉远远不止提示头部界面,所以这一步,先反弹回仅显示提示头部界面,然后提示用户”正在加载”。
(4). 加载完成后,隐藏提示头部界面。
那么让我们看看怎么才能实现呢???
第一步:既然是要显示listview ,那么就应该有个listview 的容器pulldown.xml
<?xml version="1.0" encoding="utf-8"?> <com.solo.pulldown.pulldownview xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pull_down_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/white"> </com.solo.pulldown.pulldownview>
第二步:自定义一个listview中显示的item对象pulldown_item.xml
<?xml version="1.0" encoding="utf-8"?> <textview xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/text1" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textappearance="?android:attr/textappearancelarge" android:gravity="center_vertical" android:paddingleft="6dip" android:minheight="?android:attr/listpreferreditemheight" android:textcolor="@android:color/black" />
第三步:定义一个header的xml布局文件pulldown_header.xml
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingbottom="10dp" android:paddingtop="10dp" > <imageview android:id="@+id/pulldown_header_arrow" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignparentleft="true" android:layout_marginleft="20dp" android:scaletype="centercrop" android:src="@drawable/z_arrow_down" android:visibility="invisible" /> <linearlayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignbottom="@+id/pulldown_header_arrow" android:layout_aligntop="@+id/pulldown_header_arrow" android:layout_centerhorizontal="true" android:gravity="center_vertical" android:orientation="vertical" > <textview android:id="@+id/pulldown_header_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="加载中..." /> <textview android:id="@+id/pulldown_header_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="更新于:" android:visibility="gone" /> </linearlayout> <progressbar android:id="@+id/pulldown_header_loading" style="@android:style/widget.progressbar.small.inverse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centervertical="true" android:layout_marginleft="20dp" /> </relativelayout>
第四步:如果需要向上拉更新更多的话,那就定义一个底部的footer的布局文件,在此为方便起见,只定义一个progressbar跟textview,更加复杂的显示,就交给你们了~~~~~pulldown_footer.xml:
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingbottom="10dp" android:paddingtop="10dp" > <textview android:id="@+id/pulldown_footer_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerinparent="true" android:text="更多" android:textsize="15dp" /> <progressbar android:id="@+id/pulldown_footer_loading" style="@android:style/widget.progressbar.small.inverse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centervertical="true" android:layout_marginleft="20dp" android:visibility="gone" /> </relativelayout>
第五步:那么主要的文件这才登场:::::::重写listview这个文件主要任务是提供触摸的事件的处理方法。
/** * <p>一个可以监听listview是否滚动到最顶部或最底部的自定义控件</p> * 只能监听由触摸产生的,如果是listview本身flying导致的,则不能监听</br> * 如果加以改进,可以实现监听scroll滚动的具体位置等 */ public class scrolloverlistview extends listview { private int mlasty; private int mtopposition; private int mbottomposition; public scrolloverlistview(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(); } public scrolloverlistview(context context, attributeset attrs) { super(context, attrs); init(); } public scrolloverlistview(context context) { super(context); init(); } private void init(){ mtopposition = 0; mbottomposition = 0; } @override public boolean ontouchevent(motionevent ev) { final int action = ev.getaction(); final int y = (int) ev.getrawy(); switch(action){ case motionevent.action_down:{ mlasty = y; final boolean ishandled = monscrolloverlistener.onmotiondown(ev); if (ishandled) { mlasty = y; return ishandled; } break; } case motionevent.action_move:{ final int childcount = getchildcount(); if(childcount == 0) return super.ontouchevent(ev); final int itemcount = getadapter().getcount() - mbottomposition; final int deltay = y - mlasty; //dlog.d("lasty=%d y=%d", mlasty, y); final int firsttop = getchildat(0).gettop(); final int listpadding = getlistpaddingtop(); final int lastbottom = getchildat(childcount - 1).getbottom(); final int end = getheight() - getpaddingbottom(); final int firstvisibleposition = getfirstvisibleposition(); final boolean ishandlemotionmove = monscrolloverlistener.onmotionmove(ev, deltay); if(ishandlemotionmove){ mlasty = y; return true; } //dlog.d("firstvisibleposition=%d firsttop=%d listpaddingtop=%d deltay=%d", firstvisibleposition, firsttop, listpadding, deltay); if (firstvisibleposition <= mtopposition && firsttop >= listpadding && deltay > 0) { final boolean ishandleonlistviewtopandpulldown; ishandleonlistviewtopandpulldown = monscrolloverlistener.onlistviewtopandpulldown(deltay); if(ishandleonlistviewtopandpulldown){ mlasty = y; return true; } } // dlog.d("lastbottom=%d end=%d deltay=%d", lastbottom, end, deltay); if (firstvisibleposition + childcount >= itemcount && lastbottom <= end && deltay < 0) { final boolean ishandleonlistviewbottomandpulldown; ishandleonlistviewbottomandpulldown = monscrolloverlistener.onlistviewbottomandpullup(deltay); if(ishandleonlistviewbottomandpulldown){ mlasty = y; return true; } } break; } case motionevent.action_up:{ final boolean ishandlermotionup = monscrolloverlistener.onmotionup(ev); if (ishandlermotionup) { mlasty = y; return true; } break; } } mlasty = y; return super.ontouchevent(ev); } /**空的*/ private onscrolloverlistener monscrolloverlistener = new onscrolloverlistener(){ @override public boolean onlistviewtopandpulldown(int delta) { return false; } @override public boolean onlistviewbottomandpullup(int delta) { return false; } @override public boolean onmotiondown(motionevent ev) { return false; } @override public boolean onmotionmove(motionevent ev, int delta) { return false; } @override public boolean onmotionup(motionevent ev) { return false; } }; // =============================== public method =============================== /** * 可以自定义其中一个条目为头部,头部触发的事件将以这个为准,默认为第一个 * * @param index 正数第几个,必须在条目数范围之内 */ public void settopposition(int index){ if(getadapter() == null) throw new nullpointerexception("you must set adapter before settopposition!"); if(index < 0) throw new illegalargumentexception("top position must > 0"); mtopposition = index; } /** * 可以自定义其中一个条目为尾部,尾部触发的事件将以这个为准,默认为最后一个 * * @param index 倒数第几个,必须在条目数范围之内 */ public void setbottomposition(int index){ if(getadapter() == null) throw new nullpointerexception("you must set adapter before setbottonposition!"); if(index < 0) throw new illegalargumentexception("bottom position must > 0"); mbottomposition = index; } /** * 设置这个listener可以监听是否到达顶端,或者是否到达低端等事件</br> * * @see onscrolloverlistener */ public void setonscrolloverlistener(onscrolloverlistener onscrolloverlistener){ monscrolloverlistener = onscrolloverlistener; } /** * 滚动监听接口</br> * @see scrolloverlistview#setonscrolloverlistener(onscrolloverlistener) * */ public interface onscrolloverlistener { /** * 到达最顶部触发 * * @param delta 手指点击移动产生的偏移量 * @return */ boolean onlistviewtopandpulldown(int delta); /** * 到达最底部触发 * * @param delta 手指点击移动产生的偏移量 * @return */ boolean onlistviewbottomandpullup(int delta); /** * 手指触摸按下触发,相当于{@link motionevent#action_down} * * @return 返回true表示自己处理 * @see view#ontouchevent(motionevent) */ boolean onmotiondown(motionevent ev); /** * 手指触摸移动触发,相当于{@link motionevent#action_move} * * @return 返回true表示自己处理 * @see view#ontouchevent(motionevent) */ boolean onmotionmove(motionevent ev, int delta); /** * 手指触摸后提起触发,相当于{@link motionevent#action_up} * * @return 返回true表示自己处理 * @see view#ontouchevent(motionevent) */ boolean onmotionup(motionevent ev); } }
第六步:下拉刷新控件,真正实现下拉刷新的是这个控件,而上面的那个scrolloverlistview只是提供触摸的事件等
/** * 下拉刷新控件</br> * 真正实现下拉刷新的是这个控件, * scrolloverlistview只是提供触摸的事件等 */ public class pulldownview extends linearlayout implements onscrolloverlistener{ private static final string tag = "pulldownview"; private static final int start_pull_deviation = 50; // 移动误差 private static final int auto_incremental = 10; // 自增量,用于回弹 private static final int what_did_load_data = 1; // handler what 数据加载完毕 private static final int what_on_refresh = 2; // handler what 刷新中 private static final int what_did_refresh = 3; // handler what 已经刷新完 private static final int what_set_header_height = 4;// handler what 设置高度 private static final int what_did_more = 5; // handler what 已经获取完更多 private static final int default_header_view_height = 105; // 头部文件原本的高度 private static simpledateformat dateformat = new simpledateformat("mm-dd hh:mm"); private view mheaderview; private layoutparams mheaderviewparams; private textview mheaderviewdateview; private textview mheadertextview; private imageview mheaderarrowview; private view mheaderloadingview; private view mfooterview; private textview mfootertextview; private view mfooterloadingview; private scrolloverlistview mlistview; private onpulldownlistener monpulldownlistener; private rotateanimation mrotateoto180animation; private rotateanimation mrotate180to0animation; private int mheaderincremental; // 增量 private float mmotiondownlasty; // 按下时候的y轴坐标 private boolean misdown; // 是否按下 private boolean misrefreshing; // 是否下拉刷新中 private boolean misfetchmoreing; // 是否获取更多中 private boolean mispullupdone; // 是否回推完成 private boolean menableautofetchmore; // 是否允许自动获取更多 // 头部文件的状态 private static final int header_view_state_idle = 0; // 空闲 private static final int header_view_state_not_over_height = 1; // 没有超过默认高度 private static final int header_view_state_over_height = 2; // 超过默认高度 private int mheaderviewstate = header_view_state_idle; public pulldownview(context context, attributeset attrs) { super(context, attrs); initheaderviewandfooterviewandlistview(context); } public pulldownview(context context) { super(context); initheaderviewandfooterviewandlistview(context); } /* * ================================== * public method * 外部使用,具体就是用这几个就可以了 * * ================================== */ /** * 刷新事件接口 */ public interface onpulldownlistener { void onrefresh(); void onmore(); } /** * 通知加载完了数据,要放在adapter.notifydatasetchanged后面 * 当你加载完数据的时候,调用这个notifydidload() * 才会隐藏头部,并初始化数据等 */ public void notifydidload() { muihandler.sendemptymessage(what_did_load_data); } /** * 通知已经刷新完了,要放在adapter.notifydatasetchanged后面 * 当你执行完刷新任务之后,调用这个notifydidrefresh() * 才会隐藏掉头部文件等操作 */ public void notifydidrefresh() { muihandler.sendemptymessage(what_did_refresh); } /** * 通知已经获取完更多了,要放在adapter.notifydatasetchanged后面 * 当你执行完更多任务之后,调用这个notyfydidmore() * 才会隐藏加载圈等操作 */ public void notifydidmore() { muihandler.sendemptymessage(what_did_more); } /** * 设置监听器 * @param listener */ public void setonpulldownlistener(onpulldownlistener listener){ monpulldownlistener = listener; } /** * 获取内嵌的listview * @return scrolloverlistview */ public listview getlistview(){ return mlistview; } /** * 是否开启自动获取更多 * 自动获取更多,将会隐藏footer,并在到达底部的时候自动刷新 * @param index 倒数第几个触发 */ public void enableautofetchmore(boolean enable, int index){ if(enable){ mlistview.setbottomposition(index); mfooterloadingview.setvisibility(view.visible); }else{ mfootertextview.settext("更多"); mfooterloadingview.setvisibility(view.gone); } menableautofetchmore = enable; } /* * ================================== * private method * 具体实现下拉刷新等操作 * * ================================== */ /** * 初始化界面 */ private void initheaderviewandfooterviewandlistview(context context){ setorientation(linearlayout.vertical); //setdrawingcacheenabled(false); /* * 自定义头部文件 * 放在这里是因为考虑到很多界面都需要使用 * 如果要修改,和它相关的设置都要更改 */ mheaderview = layoutinflater.from(context).inflate(r.layout.pulldown_header, null); mheaderviewparams = new layoutparams(layoutparams.fill_parent, layoutparams.wrap_content); addview(mheaderview, 0, mheaderviewparams); mheadertextview = (textview) mheaderview.findviewbyid(r.id.pulldown_header_text); mheaderarrowview = (imageview) mheaderview.findviewbyid(r.id.pulldown_header_arrow); mheaderloadingview = mheaderview.findviewbyid(r.id.pulldown_header_loading); // 注意,图片旋转之后,再执行旋转,坐标会重新开始计算 mrotateoto180animation = new rotateanimation(0, 180, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); mrotateoto180animation.setduration(250); mrotateoto180animation.setfillafter(true); mrotate180to0animation = new rotateanimation(180, 0, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f); mrotate180to0animation.setduration(250); mrotate180to0animation.setfillafter(true); /** * 自定义脚部文件 */ mfooterview = layoutinflater.from(context).inflate(r.layout.pulldown_footer, null); mfootertextview = (textview) mfooterview.findviewbyid(r.id.pulldown_footer_text); mfooterloadingview = mfooterview.findviewbyid(r.id.pulldown_footer_loading); mfooterview.setonclicklistener(new onclicklistener() { @override public void onclick(view v) { if(!misfetchmoreing){ misfetchmoreing = true; mfooterloadingview.setvisibility(view.visible); monpulldownlistener.onmore(); } } }); /* * scrolloverlistview 同样是考虑到都是使用,所以放在这里 * 同时因为,需要它的监听事件 */ mlistview = new scrolloverlistview(context); mlistview.setonscrolloverlistener(this); mlistview.setcachecolorhint(0); addview(mlistview, layoutparams.fill_parent, layoutparams.fill_parent); // 空的listener monpulldownlistener = new onpulldownlistener() { @override public void onrefresh() {} @override public void onmore() {} }; } /** * 在下拉和回推的时候检查头部文件的状态</br> * 如果超过了默认高度,就显示松开可以刷新, * 否则显示下拉可以刷新 */ private void checkheaderviewstate(){ if(mheaderviewparams.height >= default_header_view_height){ if(mheaderviewstate == header_view_state_over_height) return; mheaderviewstate = header_view_state_over_height; mheadertextview.settext("松开可以刷新"); mheaderarrowview.startanimation(mrotateoto180animation); }else{ if(mheaderviewstate == header_view_state_not_over_height || mheaderviewstate == header_view_state_idle) return; mheaderviewstate = header_view_state_not_over_height; mheadertextview.settext("下拉可以刷新"); mheaderarrowview.startanimation(mrotate180to0animation); } } private void setheaderheight(final int height){ mheaderincremental = height; mheaderviewparams.height = height; mheaderview.setlayoutparams(mheaderviewparams); } /** * 自动隐藏动画 */ class hideheaderviewtask extends timertask{ @override public void run() { if(misdown) { cancel(); return; } mheaderincremental -= auto_incremental; if(mheaderincremental > 0){ muihandler.sendemptymessage(what_set_header_height); }else{ mheaderincremental = 0; muihandler.sendemptymessage(what_set_header_height); cancel(); } } } /** * 自动显示动画 */ class showheaderviewtask extends timertask{ @override public void run() { if(misdown) { cancel(); return; } mheaderincremental -= auto_incremental; if(mheaderincremental > default_header_view_height){ muihandler.sendemptymessage(what_set_header_height); }else{ mheaderincremental = default_header_view_height; muihandler.sendemptymessage(what_set_header_height); if(!misrefreshing){ misrefreshing = true; muihandler.sendemptymessage(what_on_refresh); } cancel(); } } } private handler muihandler = new handler(){ @override public void handlemessage(message msg) { switch (msg.what) { case what_did_load_data:{ mheaderviewparams.height = 0; mheaderloadingview.setvisibility(view.gone); mheadertextview.settext("下拉可以刷新"); mheaderviewdateview = (textview) mheaderview.findviewbyid(r.id.pulldown_header_date); mheaderviewdateview.setvisibility(view.visible); mheaderviewdateview.settext("更新于:" + dateformat.format(new date(system.currenttimemillis()))); mheaderarrowview.setvisibility(view.visible); showfooterview(); return; } case what_on_refresh:{ // 要清除掉动画,否则无法隐藏 mheaderarrowview.clearanimation(); mheaderarrowview.setvisibility(view.invisible); mheaderloadingview.setvisibility(view.visible); monpulldownlistener.onrefresh(); return; } case what_did_refresh :{ misrefreshing = false; mheaderviewstate = header_view_state_idle; mheaderarrowview.setvisibility(view.visible); mheaderloadingview.setvisibility(view.gone); mheaderviewdateview.settext("更新于:" + dateformat.format(new date(system.currenttimemillis()))); setheaderheight(0); showfooterview(); return; } case what_set_header_height :{ setheaderheight(mheaderincremental); return; } case what_did_more :{ misfetchmoreing = false; mfootertextview.settext("更多"); mfooterloadingview.setvisibility(view.gone); } } } }; /** * 显示脚步脚部文件 */ private void showfooterview(){ if(mlistview.getfooterviewscount() == 0 && isfillscreenitem()){ mlistview.addfooterview(mfooterview); mlistview.setadapter(mlistview.getadapter()); } } /** * 条目是否填满整个屏幕 */ private boolean isfillscreenitem(){ final int firstvisibleposition = mlistview.getfirstvisibleposition(); final int lastvisiblepostion = mlistview.getlastvisibleposition() - mlistview.getfooterviewscount(); final int visibleitemcount = lastvisiblepostion - firstvisibleposition + 1; final int totalitemcount = mlistview.getcount() - mlistview.getfooterviewscount(); if(visibleitemcount < totalitemcount) return true; return false; } /* * ================================== * 实现 onscrolloverlistener接口 * * * ================================== */ @override public boolean onlistviewtopandpulldown(int delta) { if(misrefreshing || mlistview.getcount() - mlistview.getfooterviewscount() == 0) return false; int absdelta = math.abs(delta); final int i = (int) math.ceil((double)absdelta / 2); mheaderincremental += i; if(mheaderincremental >= 0){ // && mincremental <= mmaxheight setheaderheight(mheaderincremental); checkheaderviewstate(); } return true; } @override public boolean onlistviewbottomandpullup(int delta) { if(!menableautofetchmore || misfetchmoreing) return false; // 数量充满屏幕才触发 if(isfillscreenitem()){ misfetchmoreing = true; mfootertextview.settext("加载更多中..."); mfooterloadingview.setvisibility(view.visible); monpulldownlistener.onmore(); return true; } return false; } @override public boolean onmotiondown(motionevent ev) { misdown = true; mispullupdone = false; mmotiondownlasty = ev.getrawy(); return false; } @override public boolean onmotionmove(motionevent ev, int delta) { //当头部文件回推消失的时候,不允许滚动 if(mispullupdone) return true; // 如果开始按下到滑动距离不超过误差值,则不滑动 final int absmotiony = (int) math.abs(ev.getrawy() - mmotiondownlasty); if(absmotiony < start_pull_deviation) return true; final int absdelta = math.abs(delta); final int i = (int) math.ceil((double)absdelta / 2); // ontopdown在顶部,并上回推和ontopup相对 if(mheaderviewparams.height > 0 && delta < 0){ mheaderincremental -= i; if(mheaderincremental > 0){ setheaderheight(mheaderincremental); checkheaderviewstate(); }else{ mheaderviewstate = header_view_state_idle; mheaderincremental = 0; setheaderheight(mheaderincremental); mispullupdone = true; } return true; } return false; } @override public boolean onmotionup(motionevent ev) { misdown = false; // 避免和点击事件冲突 if(mheaderviewparams.height > 0){ // 判断头文件拉动的距离与设定的高度,小了就隐藏,多了就固定高度 int x = mheaderincremental - default_header_view_height; timer timer = new timer(true); if(x < 0){ timer.scheduleatfixedrate(new hideheaderviewtask(), 0, 10); }else{ timer.scheduleatfixedrate(new showheaderviewtask(), 0, 10); } return true; } return false; } }
第七步:这个java文件就是封装数据,然后调用上两个文件就好了。废话不多说,上代码:::::
public class pulldownactivity extends activity implements onpulldownlistener, onitemclicklistener{ private static final int what_did_load_data = 0; private static final int what_did_refresh = 1; private static final int what_did_more = 2; private listview mlistview; private arrayadapter<string> madapter; private pulldownview mpulldownview; private list<string> mstrings = new arraylist<string>(); @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.pulldown); /* * 1.使用pulldownview * 2.设置onpulldownlistener * 3.从mpulldownview里面获取listview */ mpulldownview = (pulldownview) findviewbyid(r.id.pull_down_view); mpulldownview.setonpulldownlistener(this); mlistview = mpulldownview.getlistview(); mlistview.setonitemclicklistener(this); madapter = new arrayadapter<string>(this, r.layout.pulldown_item, mstrings); mlistview.setadapter(madapter); mpulldownview.enableautofetchmore(true, 1); loaddata(); } private void loaddata(){ new thread(new runnable() { @override public void run() { try { thread.sleep(2000); } catch (interruptedexception e) { e.printstacktrace(); } list<string> strings = new arraylist<string>(); for (string body : mstringarray) { strings.add(body); } message msg = muihandler.obtainmessage(what_did_load_data); msg.obj = strings; msg.sendtotarget(); } }).start(); } @override public void onrefresh() { new thread(new runnable() { @override public void run() { try { thread.sleep(2000); } catch (interruptedexception e) { e.printstacktrace(); } message msg = muihandler.obtainmessage(what_did_refresh); msg.obj = "after refresh " + system.currenttimemillis(); msg.sendtotarget(); } }).start(); } @override public void onmore() { new thread(new runnable() { @override public void run() { try { thread.sleep(2000); } catch (interruptedexception e) { e.printstacktrace(); } message msg = muihandler.obtainmessage(what_did_more); msg.obj = "after more " + system.currenttimemillis(); msg.sendtotarget(); } }).start(); } private handler muihandler = new handler(){ @override public void handlemessage(message msg) { switch (msg.what) { case what_did_load_data:{ if(msg.obj != null){ list<string> strings = (list<string>) msg.obj; if(!strings.isempty()){ mstrings.addall(strings); madapter.notifydatasetchanged(); } } // 诉它数据加载完毕; mpulldownview.notifydidload(); break; } case what_did_refresh :{ string body = (string) msg.obj; mstrings.add(0, body); madapter.notifydatasetchanged(); // 告诉它更新完毕 mpulldownview.notifydidrefresh(); break; } case what_did_more:{ string body = (string) msg.obj; mstrings.add(body); madapter.notifydatasetchanged(); // 告诉它获取更多完毕 mpulldownview.notifydidmore(); break; } } } }; @override public void onitemclick(adapterview<?> parent, view view, int position, long id) { toast.maketext(this, "啊,你点中我了 " + position, toast.length_short).show(); } // 模拟数据 private string[] mstringarray = { "abbaye de belloc", "abbaye du mont des cats", "abertam", "abondance", "ackawi", "acorn", "adelost", "affidelice au chablis", "afuega'l pitu", "airag", "airedale", "aisy cendre", "allgauer emmentaler", "alverca", "ambert", "american cheese" }; }
整个程序就这么完成了,总之,可以使用前两个封装好的文件,然后,调用就好了~~~~没什么太难的地方。
以上所述是小编给大家介绍的android程序开发之listview下拉刷新上拉(滑动分页)加载更多,希望对大家有所帮助
推荐阅读
-
Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多
-
Android ListView下拉刷新上拉自动加载更多DEMO示例
-
Android开发ListView中下拉刷新上拉加载及带列的横向滚动实现方法
-
Android程序开发之使用PullToRefresh实现下拉刷新和上拉加载
-
Android开发ListView中下拉刷新上拉加载及带列的横向滚动实现方法
-
Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多
-
Android ListView实现上拉加载更多和下拉刷新功能
-
Android ListView实现上拉加载更多和下拉刷新功能
-
Android ListView实现上拉加载下拉刷新和滑动删除功能
-
Android中Listview下拉刷新和上拉加载更多的多种实现方案