自定义ListView下拉刷新的功能,给出一个不完整的东西,仅作思路和笔记:
代码参考了http://www.imooc.com/learn/135,一些地方做了自己的优化
public class DragList extends ListView implements OnScrollListener {
// 下拉头的View和子View
View header;
TextView tip;
TextView lastupdate_time;
ImageView arrow;
ProgressBar progress;
// 下拉头高度
int headerHeight;
// 下拉刷新的回调
PullRefreshListener onPullListener;
// 下拉状态下的header的几个状态
final int NORMAL = 0;
final int PULL = 1;
final int REFRESH = 2;
final int REFRESHING = 3;
// 用于控制onLayout只执行一次
private boolean once = true;
// listView第一个可见item的pos,用于指示listView,只有在这个值是0,
//即目前header刚好隐藏在屏幕上方时才开始动态设置header的toppadding使之有隐藏显示的效果
int firstVisibleItem;
int yDown;
int yMove;//move过程中y坐标
boolean mark;// 如果是在顶端,才可以拉下去,否则不能拉至header(配合firstVisibleItem使用)
int space;//一次的下拉距离
int state = NORMAL;//初始状态
// 没有使用自定义属性,系统调用两个参数的构造
public DragList(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
// 使用系统的measure进行空间测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// 隐藏header,方法是设置header的toppadding值为负的自身高度。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (once) {
headerHeight = header.getMeasuredHeight();
topPadding(-headerHeight);
once = false;
}
}
// 简单的初始化和滚动监听
private void initView(Context context) {
LayoutInflater inflate = LayoutInflater.from(context);
header = inflate.inflate(R.layout.header_layout, null);
tip = (TextView) header.findViewById(R.id.tip);
lastupdate_time = (TextView) header.findViewById(R.id.lastupdate_time);
arrow = (ImageView) header.findViewById(R.id.arrow);
progress = (ProgressBar) header.findViewById(R.id.progress);
this.addHeaderView(header);
this.setOnScrollListener(this);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
//监听Scroll时间,设置当前ListView的第一个item,header是第0个,一般情况下,当ListView滑动到第1个item时,上边缘贴住父View的上边缘,这时ListView
//的第一个item就是0,即可以理解为,item之间的devider属于上面的一个item,
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
this.firstVisibleItem = firstVisibleItem;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if (firstVisibleItem == 0) {
mark = true;
yDown = (int) ev.getY();
}
break;
case MotionEvent.ACTION_MOVE:
//这个方法主要任务是设置state的状态值,具体工作在Up中
onMove(ev);
break;
case MotionEvent.ACTION_UP:
if (state == REFRESH) {
state = REFRESHING;
updateHeader();
// 做一些数据刷新的工作,这个由具体对象设置
onPullListener.onPull();
} else if (state == PULL) {
state = NORMAL;
mark = false;
updateHeader();
}
break;
}
return super.onTouchEvent(ev);
}
private void onMove(MotionEvent ev) {
if (!mark) {
return;
}
yMove = (int) ev.getY();
space = yMove - yDown;
int topPadding = space - headerHeight;
switch (state) {
case NORMAL:
//下拉情况
if (space > 0) {
state = PULL;
updateHeader();
}
break;
case PULL:
//PULL状态表示还没达到一个阈值
topPadding(topPadding);
//距离大于这个值表示松开就刷新了
if (space > headerHeight + 40) {
state = REFRESH;
updateHeader();
}
break;
case REFRESH:
// if (topPadding > 100)
// return;
topPadding(topPadding);
//达到状态REFRESH但是又滑回去了,状态值重置
if (space < headerHeight + 40) {
state = PULL;
updateHeader();
} else if (space < 0) {
state = NORMAL;
updateHeader();
}
break;
}
}
private void updateHeader() {
switch (state) {
case NORMAL:
topPadding(-headerHeight);
break;
case PULL:
arrow.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
tip.setText("下拉可以刷新!");
break;
case REFRESH:
arrow.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
tip.setText("松开可以刷新!");
break;
case REFRESHING:
//这个状态下由于没有方法将state设置回去,state一直保持REFRESHING,所以无法向下滑动动态设置header的toppadding
//具体使用时需要完善
arrow.setVisibility(View.GONE);
progress.setVisibility(View.VISIBLE);
tip.setText("正在刷新...");
break;
}
}
private void topPadding(int topPadding) {
header.setPadding(header.getPaddingLeft(), topPadding,
header.getPaddingRight(), header.getPaddingBottom());
header.invalidate();
}
public interface PullRefreshListener {
void onPull();
}
public void setOnPullListener(PullRefreshListener onPullListener) {
this.onPullListener = onPullListener;
}
}