实现ListView的下拉刷新和上拉加载,需要先添加headerView和footerView,通过在拖动的过程中,控制头尾布局的paddingTop实现。先把paddingTop设为负值,来隐藏header,在下拉的过程中,不断改变headerView的paddingTop,实现下拉过程中headerView慢慢显示的效果。
下拉刷新有3种状态:
- 下拉刷新:headerView开始慢慢显示到完全显示出来
- 释放刷新:headerView完全显示出来,但是你还在下拉,move没有停止
- 刷新你中:headerView完全显示出来,手指离开屏幕 ACTION_UP
添加headerView
首先我们继承ListView,在构造方法中添加headerView
public class RefreshListView extends ListView implements AbsListView.OnScrollListener {
public RefreshListView(Context context) {
this(context, null);
}
public RefreshListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public RefreshListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initHeaderView();
}
}
添加headerView
private void initHeaderView() {
headerView = View.inflate(getContext(), R.layout.header_view, null);
tvStateHeader = headerView.findViewById(R.id.tv_state_header);
headerView.measure(0, 0);
headerViewHeight = headerView.getMeasuredHeight();
headerView.setPadding(0, -headerViewHeight, 0, 0);
addHeaderView(headerView);
}
move中进行状态判断
我们在move过程中实现下拉
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE:
moveY = (int) ev.getY();
int instance = moveY - downY;
if (instance > 0 ) {
int paddingTop = -headerViewHeight + instance;
headerView.setPadding(0, paddingTop, 0, 0);
return true;
}
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onTouchEvent(ev);
}
先要明白一点:在move过程中,根据下拉距离 设置不同的state ,up时再根据state执行相应的操作。
//设置3种下拉刷新状态
public final int DOWN_REFRESH = 1;
public final int RELEASE_REFRESH = 2;
public final int REFRESHING = 3;
private int currentState = DOWN_REFRESH;//当前状态是下拉刷新
我们知道MotionEvent有3种常见的action, ACTION_DOWN:按下;ACTION_MOVE:移动;ACTION_UP:手指抬起。
在move过程中的对应2个状态:下拉刷新和释放刷新。当下拉距离达到headerView高度前是下拉刷新状态,超过此高度是释放刷新状态,当然条件是我们自己定的,也可以是下拉距离超过1.5倍headerViewHeight才是释放刷新。
up过程中对应的2个状态:下拉刷新和释放刷新。当时下拉刷新状态时,up后headerView隐藏;当释放刷新状态时,up后进行刷新操作。
move过程中,进行刷新操作需满足3个条件:
1. 是下拉不是上滑,即 moveY - downY必须大于0
2. 当前页第一个可见的item的position==0
3. 当前状态不是刷新中
代码如下:
case MotionEvent.ACTION_MOVE:
moveY = (int) ev.getY();
int instance = moveY - downY;
if (instance > 0 && getFirstVisiblePosition() == 0 && currentStateHeader != REFRESHING) {
int paddingTop = -headerViewHeight + instance;
if (paddingTop < 0) {//&& currentStateHeader != RELEASE_REFRESH
currentStateHeader = DOWN_REFRESH;
tvStateHeader.setText("下拉刷新");
} else if (paddingTop > 0) {//&& currentStateHeader == DOWN_REFRESH
currentStateHeader = RELEASE_REFRESH;
tvStateHeader.setText("释放刷新");
}
//对paddingTop进行限制,paddingTop<=3*headerViewHeight
if (paddingTop > 3 * headerViewHeight) {
headerView.setPadding(0, 3 * headerViewHeight, 0, 0);
} else {
headerView.setPadding(0, paddingTop, 0, 0);
}
return true;
}
break;
如果继续下拉的话,会一直滑到底部,所以上面对下滑距离进行了限制,最多为3个headerViewheight。
up中进行刷新操作
当手指移开屏幕后,
若当前是下拉刷新状态,则隐藏headerView。
若当前是释放刷新状态,则执行刷新操作。
若当前是刷新中,则不做任何操作。
case MotionEvent.ACTION_UP:
if (currentStateHeader == RELEASE_REFRESH) {
//刷新中
currentStateHeader = REFRESHING;
headerView.setPadding(0, 0, 0, 0);
tvStateHeader.setText("刷新中");
if (onRefreshListener != null) {
onRefreshListener.refresh();
}
} else if (currentStateHeader == DOWN_REFRESH) {
headerView.setPadding(0, -headerViewHeight, 0, 0);
}
break;
刷新回调:
public interface OnRefreshListener {
void refresh();
}
private OnRefreshListener onRefreshListener;
public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
this.onRefreshListener = onRefreshListener;
}
在activity中使用回调
listView.setOnRefreshListener(new ListView2.OnRefreshListener() {
@Override
public void refresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
dataList.add(0,"header");
adapter.notifyDataSetChanged();
listView.finishRefresh();
}
},2000);
}
});
上面的listView.finishRefresh();是结束刷新,需要隐藏headerView,并把当前状态设为下拉刷新。
public void finishRefresh() {
headerView.setPadding(0, -headerViewHeight, 0, 0);
currentStateHeader = DOWN_REFRESH;
}
下拉刷新中的动画处理
当结束刷新的时候记得清楚动画
view.clearAnimation()
« textView边框
|
实现ListView上拉加载»
|