android开发教程之实现listview下拉刷新和上拉刷新效果
public class pulltoloadlistview extends listview implements onscrolllistener {
private static final string tag = pulltoloadlistview.class.getsimplename();
private static final int state_non = 0;
private static final int state_pull_to_refresh = 1;
private static final int state_release_to_refresh = 2;
private static final int state_refreshing = 3;
private int state;
private int firstvisibleitem;
private int lastvisisibleitem;
private float prevy = 0;
private view headerview;
private view footerview;
// header widgets
private progressbar headerprogressbar;
private imageview headerimagearrow;
private textview headertext;
private rotateanimation headerarrowanim;
private rotateanimation headerarrowreverseanim;
// footer widgets
private progressbar footerprogressbar;
private textview footertext;
private boolean headerishanding = false;
private boolean footerishanding = false;
private int headerheight;
private int footerheight;
private resetanimation resetanim;
private onloadinglistener onloadinglistener;
private onscrolllistener onscrolllistener;
public pulltoloadlistview(context context) {
super(context);
init(context);
}
public pulltoloadlistview(context context, attributeset attrs) {
super(context, attrs);
init(context);
}
private void init(context context) {
state = state_non;
firstvisibleitem = 0;
lastvisisibleitem = 0;
layoutinflater inflater = layoutinflater.from(context);
headerview = inflater.inflate(r.layout.view_pull_header, null);
footerview = inflater.inflate(r.layout.view_pull_footer, null);
headerprogressbar = (progressbar) headerview.findviewbyid(r.id.progressbar);
headerimagearrow = (imageview) headerview.findviewbyid(r.id.arrow);
headertext = (textview) headerview.findviewbyid(r.id.text);
headerarrowanim = new rotateanimation(0, -180, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f);
headerarrowanim.setduration(300);
headerarrowanim.setfillafter(true);
headerarrowreverseanim = new rotateanimation(-180, 0, animation.relative_to_self, 0.5f, animation.relative_to_self, 0.5f);
headerarrowreverseanim.setduration(300);
headerarrowreverseanim.setfillafter(true);
footerprogressbar = (progressbar) footerview.findviewbyid(r.id.progressbar);
footertext = (textview) footerview.findviewbyid(r.id.text);
measureview(headerview);
measureview(footerview);
headerheight = headerview.getmeasuredheight();
footerheight = footerview.getmeasuredheight();
headerview.setpadding(0, -1 * headerview.getmeasuredheight(), 0, 0);
footerview.setpadding(0, -1 * footerview.getmeasuredheight(), 0, 0);
headerview.invalidate();
footerview.invalidate();
addheaderview(headerview, null, false);
addfooterview(footerview, null, false);
super.setonscrolllistener(this);
}
private void measureview(view view) {
viewgroup.layoutparams lp = view.getlayoutparams();
if(lp == null) {
lp = new viewgroup.layoutparams(viewgroup.layoutparams.match_parent, viewgroup.layoutparams.wrap_content);
}
int childwidthspec = viewgroup.getchildmeasurespec(0, 0, lp.width);
int childheightspec;
if(lp.height > 0) {
childheightspec = measurespec.makemeasurespec(0, measurespec.exactly);
} else {
childheightspec = measurespec.makemeasurespec(0, measurespec.unspecified);
}
view.measure(childwidthspec, childheightspec);
}
private void resetheader() {
// headerview.setpadding(0, -1 * headerheight, 0, 0);
resetanim = new resetanimation(headerview, headerheight, headerview.getpaddingtop());
resetanim.start();
}
private void resetfooter() {
resetanim = new resetanimation(footerview, footerheight, footerview.getpaddingtop());
resetanim.start();
}
private void changeheaderviewbystate(int state) {
if(this.state == state) {
return ;
}
int prevstate = this.state;
this.state = state;
switch(state) {
case state_non:
headerprogressbar.setvisibility(view.invisible);
headerimagearrow.setvisibility(view.visible);
headerimagearrow.clearanimation();
headertext.settext("pull down to refresh");
break;
case state_pull_to_refresh:
headerprogressbar.setvisibility(view.invisible);
headerimagearrow.setvisibility(view.visible);
headertext.settext("pull down to refresh");
if(prevstate == state_release_to_refresh) {
headerimagearrow.startanimation(headerarrowreverseanim);
} else {
headerimagearrow.clearanimation();
}
break;
case state_release_to_refresh:
headerprogressbar.setvisibility(view.invisible);
headerimagearrow.setvisibility(view.visible);
headerimagearrow.startanimation(headerarrowanim);
headertext.settext("release to refresh");
break;
case state_refreshing:
headerprogressbar.setvisibility(view.visible);
headerimagearrow.setvisibility(view.invisible);
headerimagearrow.clearanimation();
headertext.settext("refreshing");
break;
default:
break;
}
}
private void changefooterviewbystate(int state) {
if(this.state == state) {
return ;
}
this.state = state;
switch(state) {
case state_non:
footerprogressbar.setvisibility(view.invisible);
footertext.settext("pull up to refresh");
break;
case state_pull_to_refresh:
footerprogressbar.setvisibility(view.invisible);
footertext.settext("pull up to refresh");
break;
case state_release_to_refresh:
footerprogressbar.setvisibility(view.invisible);
footertext.settext("release to refresh");
break;
case state_refreshing:
footerprogressbar.setvisibility(view.visible);
footertext.settext("refreshing");
break;
default:
break;
}
}
@override
public void setonscrolllistener(onscrolllistener l) {
this.onscrolllistener = l;
}
public void setonloadinglistener(onloadinglistener onloadinglistener) {
this.onloadinglistener = onloadinglistener;
}
public void loadcompleted() {
if(headerishanding) {
changeheaderviewbystate(state_non);
resetheader();
headerishanding = false;
}
if(footerishanding) {
changefooterviewbystate(state_non);
resetfooter();
footerishanding = false;
}
}
private void handlemoveheaderevent(motionevent ev) {
headerishanding = true;
float tempy = ev.getrawy();
float vector = tempy - prevy;
vector /= 2;
prevy = tempy;
if(vector > 0) {
int newpadding = (int) (headerview.getpaddingtop() + vector);
newpadding = math.min(newpadding, headerheight / 2);
headerview.setpadding(0, newpadding, 0, 0);
if(state != state_refreshing) {
if(newpadding > 0) {
changeheaderviewbystate(state_release_to_refresh);
} else {
changeheaderviewbystate(state_pull_to_refresh);
}
}
} else {
if(state == state_release_to_refresh || state == state_pull_to_refresh) {
int newpadding = (int) (headerview.getpaddingtop() + vector);
newpadding = math.max(newpadding, -1 * headerheight);
headerview.setpadding(0, newpadding, 0, 0);
if(newpadding <= -1 * headerheight) {
changeheaderviewbystate(state_non);
headerishanding = false;
} else if(newpadding <= 0) {
changeheaderviewbystate(state_pull_to_refresh);
} else {
}
}
}
}
private void handlemovefooterevent(motionevent ev) {
footerishanding = true;
float tempy = ev.getrawy();
float vector = tempy - prevy;
vector /= 2;
prevy = tempy;
if(vector < 0) {
int newpadding = (int) (footerview.getpaddingtop() - vector);
if(newpadding > 0) {
newpadding = 0;
}
footerview.setpadding(0, newpadding, 0, 0);
if(state != state_refreshing) {
if(newpadding < 0) {
changefooterviewbystate(state_pull_to_refresh);
} else {
changefooterviewbystate(state_release_to_refresh);
}
}
} else {
int newpadding = (int) (footerview.getpaddingtop() - vector);
newpadding = math.min(newpadding, footerheight);
footerview.setpadding(0, newpadding, 0, 0);
if(newpadding <= -1 * footerheight) {
changefooterviewbystate(state_non);
footerishanding = false;
} else if(newpadding < 0) {
changefooterviewbystate(state_pull_to_refresh);
}
}
}
@override
public boolean ontouchevent(motionevent ev) {
switch(ev.getaction()) {
case motionevent.action_down:
prevy = ev.getrawy();
break;
case motionevent.action_up:
if(state == state_release_to_refresh) {
if(headerishanding) {
changeheaderviewbystate(state_refreshing);
if(onloadinglistener != null) {
onloadinglistener.onloadnew();
}
}
if(footerishanding) {
changefooterviewbystate(state_refreshing);
if(onloadinglistener != null) {
onloadinglistener.onloadmore();
}
}
} else if(state == state_pull_to_refresh) {
if(headerishanding) {
changeheaderviewbystate(state_non);
resetheader();
headerishanding = false;
}
if(footerishanding) {
changefooterviewbystate(state_non);
resetfooter();
footerishanding = false;
}
} else if(state == state_non) {
headerishanding = false;
footerishanding = false;
} else {
// state == state_refreshing
// ignore
}
break;
case motionevent.action_move:
if(resetanim == null || !resetanim.run) {
if(state != state_refreshing) {
adapter adapter = getadapter();
if(adapter == null) {
handlemoveheaderevent(ev);
} else {
final int count = adapter.getcount();
if(count <= 0) {
handlemoveheaderevent(ev);
} else {
float tempy = ev.getrawy();
float vector = tempy - prevy;
if(firstvisibleitem == 0 && lastvisisibleitem == count - 1) {
if(headerishanding) {
handlemoveheaderevent(ev);
} else if(footerishanding) {
handlemovefooterevent(ev);
} else {
if(vector > 0) {
handlemoveheaderevent(ev);
} else if(vector < 0) {
handlemovefooterevent(ev);
} else {
// ignore vector == 0
}
}
} else if(firstvisibleitem == 0 && vector > 0) {
handlemoveheaderevent(ev);
} else if(lastvisisibleitem == count - 1 && vector < 0) {
handlemovefooterevent(ev);
} else {
// ignore
}
}
}
}
}
break;
default:
break;
}
return super.ontouchevent(ev);
}
@override
public void onscrollstatechanged(abslistview view, int scrollstate) {
if(onscrolllistener != null) {
onscrolllistener.onscrollstatechanged(view, scrollstate);
}
}
@override
public void onscroll(abslistview view, int firstvisibleitem,
int visibleitemcount, int totalitemcount) {
this.firstvisibleitem = firstvisibleitem;
this.lastvisisibleitem = firstvisibleitem + visibleitemcount - 1;
if(onscrolllistener != null) {
onscrolllistener.onscroll(view, firstvisibleitem, visibleitemcount, totalitemcount);
}
}
static class resetanimation extends thread {
static final int duration = 600;
static final int interval = 5;
view view;
int orignalheight;
int paddingtop;
boolean run = false;
resetanimation(view view, int orignalheight, int paddingtop) {
this.view = view;
this.orignalheight = orignalheight;
this.paddingtop = paddingtop;
}
public void run() {
run = true;
int total = orignalheight * 2 + paddingtop;
int timetotal = duration / interval;
int piece = total / timetotal;
int time = 0;
final view view = this.view;
final int paddingtop = this.paddingtop;
do {
final int nextpaddingtop = paddingtop - time * piece;
view.post(new runnable() {
public void run() {
view.setpadding(0, nextpaddingtop, 0, 0);
view.postinvalidate();
}
});
try {
sleep(interval);
} catch (interruptedexception e) {
e.printstacktrace();
}
time ++;
} while(time < timetotal);
run = false;
}
}
public interface onloadinglistener {
public void onloadnew();
public void onloadmore();
}
}