最近看IOS的下拉效果感觉很不错,当拉倒最上面和最下面的时候继续拉动会有缓冲,想在android里面也做一个,到网上到处找,没有找到好的方法,据说android新的API对ListView有这样的支持,感觉不是特别好用。
自己利用scroller实现了一下,废话不多说了直接上代码,就一个ListViewEx类,代码很简单,有点小技巧,注释就不写了,很容易看懂
大家不好意思上次发的那个代码有点问题,这次重新修改了一下,对不住大家,发错了代码。,博客发的少,大家理解一下
import android.app.ActionBar.Tab;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.Scroller;
public class ListViewEx extends ListView implements OnScrollListener {
private float lastX;
private float lastY;
private final static float RATIO = 2.25f;
private int startY;
private int state;
private boolean isRecored;
private Scroller mScroller;
public static final int STATUS_FOOTER_IDLE = 0;
public static final int STATUS_FOOTER_LOADING = 1;
public static final int STATUS_FOOTER_DONE = 2;
public static final int STATUS_FOOTER_NET_ERROR = 3;
public static final int STATUS_FOOTER_REFRESHING = 4;
private int footerStatus = STATUS_FOOTER_IDLE;
private int lastPos, totalCount;
private boolean isBottom = false;
private boolean isTop = true;
public int getFooterStatus() {
return footerStatus;
}
public void setFooterStatus(int footerStatus) {
this.footerStatus = footerStatus;
}
public int getState() {
return state;
}
public ListViewEx(Context context) {
this(context, true);
}
public ListViewEx(Context context, boolean isEnabled) {
super(context);
init(context);
}
public ListViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mScroller = new Scroller(getContext());
setOnScrollListener(this);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (firstVisibleItem == 0) {
isTop = true;
} else {
isTop = false;
}
lastPos = view.getLastVisiblePosition();
totalCount = totalItemCount;
if (lastPos == totalCount - 1) {
isBottom = true;
} else {
isBottom = false;
}
}
float lastDx;
float lastDy;
boolean record = false;
public boolean dispatchTouchEvent(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
record = false;
lastDx = x;
lastDy = y;
break;
case MotionEvent.ACTION_MOVE: {
final float deltaX = Math.abs(x - lastDx);
final float deltaY = Math.abs(y - lastDy);
if (deltaX > 0 && deltaX > deltaY) {
record = true;
} else {
record = false;
}
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isRecored = false;
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
float x = ev.getX();
float y = ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
final float deltaX = Math.abs(x - lastX);
final float deltaY = Math.abs(y - lastY);
if (deltaX > 0 && deltaX > deltaY) {
return false;
} else {
float curY = ev.getY();
// if (curY - lastY > 0 && getScrollY() == 0) {
// top = true;
// bottom = false;
// } else if (curY - lastY < 0 && getScrollY() == getChildAt(0).getMeasuredHeight()) {
// top = false;
// bottom = false;
// } else {
// top = false;
// bottom = true;
//
// }
getParent().requestDisallowInterceptTouchEvent(false);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
requestDisallowInterceptTouchEvent(false);
break;
}
return super.onInterceptTouchEvent(ev);
}
private int distance;
@Override
public void computeScroll() {
// 先判断mScroller滚动是否完成
if (mScroller.computeScrollOffset()) {
// 这里调用View的scrollTo()完成实际的滚动
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
// 必须调用该方法,否则不一定能看到滚动效果
postInvalidate();
}
super.computeScroll();
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!isRecored) {
isRecored = true;
startY = (int) ev.getY();
}
break;
case MotionEvent.ACTION_UP:
if (isTop || isBottom) {
changeViewByState();
}
isRecored = false;
break;
case MotionEvent.ACTION_MOVE:
int tempY = (int) ev.getY();
if (!isRecored) {
isRecored = true;
startY = tempY;
}
if (isBottom && isTop) {
distance = (int) ((tempY - startY) / RATIO);
smoothTo(0, -distance);
// smoothTo(0, -distance);
} else {
if (isTop) {
if (tempY - lastY > 0) {
distance = (int) ((tempY - startY) / RATIO);
smoothTo(0, -distance);
// smoothTo(0, -distance);
}
} else if (isBottom) {
if (tempY - lastY < 0) {
distance = (int) ((tempY - startY) / RATIO);
smoothTo(0, -distance);
// smoothTo(0, -distance);
}
}
}
// else if (tempY - lastY < 0 && getScrollY() == getChildAt(0).getMeasuredHeight()) {
// distance =
// (int) ((tempY - startY) / RATIO);
// smoothTo(0, -distance);
// }
break;
default:
break;
}
return super.onTouchEvent(ev);
}
private final void smoothScrollToNormal() {
smoothTo(0, 0);
}
private void smoothTo(int fx, int fy) {
int dx = fx - mScroller.getFinalX();
int dy = fy - mScroller.getFinalY();
mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), dx, dy);
invalidate();
}
private void changeViewByState() {
smoothScrollToNormal();
distance = 0;
}
}