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

Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多

程序员文章站 2024-03-05 11:06:18
最近做的类似于微博的项目中,有个android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多。 新浪微博就是使用这种方式的典...

最近做的类似于微博的项目中,有个android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多。

新浪微博就是使用这种方式的典型。

当用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容。这时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器对应的加载第n页就好了!!!)。通过分页分次加载数据,用户看多少就去加载多少。

通常这也分为两种方式,一种是设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。今天我就和大家分享一下滑动到底端时自动加载这个功能的实现。

效果图如下所示:

Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多

Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多

Android程序开发之Listview下拉刷新上拉(滑动分页)加载更多

下拉刷新最主要的流程是:

(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下拉刷新上拉(滑动分页)加载更多,希望对大家有所帮助