之前每次 项目中用到ListView 的 下拉刷新 以及上拉分页加载 都是 用的 网上 下载 的 类库,
使用起来 诸多不便 ,于是 趁着有空 ,自己封装了ListView 让其 实现 下拉刷新,以及分页加载功能。
以下是 效果图:
当 滑动到 ListView 顶部 或 尾部 时,再次手指上拉或下拉 则会 触发 ListView 的 刷新 ,并 显示 刷新 动画,完成后动画会 缓慢消失。
Demo 下载 地址:点击打开链接
具体 实现原理:
首先对 ListView 要设置 OnScrollListener 监听 其 滑动 状态 ,并 记录此 状态。
ListView的 滑动 状态 有 三种
静止状态,SCROLL_STATE_IDLE 手指滚动状态,SCROLL_STATE_TOUCH_SCROLL 手指不动了,但是屏幕还在滚动状态。SCROLL_STATE_FLING
上下拉刷新 时 ListView的 滚动状态 必须为 手指滚动才触发刷新。
还要 对 ListView 设置 触摸 监听。
判断 ListView 的 滑动 方向,计算其 手指拖动距离,以及手指抬起时的 刷新动画的 状态
以下是 ListView 的 触摸 和 滚动 监听 代码
首先 在 滚动 监听 了 记录 当前 的 滚动状态。
然后 在 触摸监听里 当状态 为 Action.Move 移动 时,判断滚动的 方向,以及 ListView 当前位置 处于顶部还是底部,并且 是否正在刷新。
然后 根据 手指 移动的 距离 除以相应倍数 ,让 刷新动画 控件 缓慢 出现。 在Action.Up 中 判断 当前的 刷新控件 显示 的 高度 是否 触发 刷新 方法。
int currentScorllState;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
currentScorllState = scrollState;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
boolean rememberFreshYTag = true;
float freshY;
float tempY;
int times = 3;
boolean downTag = false;
float y;
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
y = motionEvent.getY();
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_MOVE:
float scrollHeight = y - tempY;
if (scrollHeight > 0) {
downTag = true;
} else {
downTag = false;
}
if (currentScorllState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
&& this.getFirstVisiblePosition() == 0
&& this.getTop() == 0
&& downTag
&& !freshingTag
) {
topFreshTag = true;
if (rememberFreshYTag) {
freshY = y;
}
rememberFreshYTag = false;
float min = Math.min(headHeight + headHeight / 2, (y - freshY) / times);
imageViewHead.setPadding(0, (int) (-headHeight + min), 0, 0);
Log.i("testss", "topFresh" + y);
} else if (currentScorllState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
&& this.getLastVisiblePosition() == getCount() - 1
&& this.getBottom() == this.getHeight()
&& !downTag
&& !freshingTag
) {
bottomFreshTag = true;
if (rememberFreshYTag) {
freshY = y;
}
rememberFreshYTag = false;
float min = Math.min(footHeight + footHeight / 2, -(y - freshY));
imageViewFoot.setPadding(0, 0, 0, (int) (-footHeight + min));
Log.i("testss", "buttomFresh" + y + "---" + freshY);
}
break;
case MotionEvent.ACTION_UP:
if (topFreshTag && !freshingTag) {
Log.i("testss", "uptopFreshTag");
// 手指 抬起时 符合 条件 则 触发 顶部刷新
judgeToFresh(TOP_FRESH, imageViewHead, headHeight);
}
if (bottomFreshTag && !freshingTag) {
// Log.i("testss", "upbottomFreshTag");
// 手指 抬起时 符合 条件 则 触发 底部刷新
judgeToFresh(BOTTOM_FRESH, imageViewFoot, footHeight);
}
break;
}
tempY = y;
return super.onTouchEvent(motionEvent);
}
以下 是判断 是否 刷新的方法
/**
* 判断 是否 触发 刷新
*
* @param freshType 刷新 的类型 顶部刷新 或 底部刷新
* @param imageView 刷新动画 的 控件
* @param height 当前 刷新动画 控件 显示 的 高度
*/
private void judgeToFresh(int freshType, ImageView imageView, int height) {
int paddingHeight = freshType == TOP_FRESH ? imageView.getPaddingTop() : imageView.getPaddingBottom();
if (paddingHeight == height / 2) {
imageView.setPadding(0, 0, 0, 0);
freshingTag = true;
if (freshType == TOP_FRESH) {
onTopFresh();
} else {
onBottomFresh();
}
} else {
dissHeadOrFootView(imageView, freshType, -paddingHeight, height);
}
}
/**
* 开始 顶部 刷新
*/
private void onTopFresh() {
// 开启 动画
startOrStopAnimation(imageViewHead, true);
/**
* 如果 设置 了外部 监听
* 则 调用 外部监听 的 刷新 方法
* 否则 过1s后 自动完成 刷新动画
*/
if (onListViewFreshListener == null) {
tempHandler.sendEmptyMessageDelayed(TOP_FRESH, 1000);
} else {
onListViewFreshListener.onTopFreshing();
}
}
/**
* 开始 底部 刷新
*/
private void onBottomFresh() {
// 开启 动画
startOrStopAnimation(imageViewFoot, true);
/**
* 如果 设置 了外部 监听
* 则 调用 外部监听 的 刷新 方法
* 否则 过1s后 自动完成 刷新动画
*/
if (onListViewFreshListener == null) {
tempHandler.sendEmptyMessageDelayed(BOTTOM_FRESH, 1000);
} else {
onListViewFreshListener.onBottomFreshing();
}
}
Demo 下载 地址:点击打开链接