暂时没有加入RecyclerView中具备的惯性滑动
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import android.widget.Scroller;
public class DraggingView extends FrameLayout {
private static final String TAG = "DraggingView";
private Scroller scroller;
private View contentView;
private int maxScrollHeight;
public DraggingView(Context context, AttributeSet attrs) {
super(context, attrs);
this.scroller = new Scroller(context);
//minSlideDistance = ViewConfiguration.get(context).getScaledTouchSlop();
minSlideDistance = 5;
}
public boolean childViewReachTop() {
if (contentView == null) {
contentView = getChildAt(0);
}
if (contentView == null) {
Log.e(TAG, "DraggingView has no child view");
return false;
}
contentView.measure(0, 0);
maxScrollHeight = contentView.getMeasuredHeight() - getMeasuredHeight();
return getScrollY() <= 0;
}
public boolean childViewReachBottom() {
if (contentView == null) {
contentView = getChildAt(0);
}
if (contentView == null) {
Log.e(TAG, "DraggingView has no child view");
return false;
}
contentView.measure(0, 0);
maxScrollHeight = contentView.getMeasuredHeight() - getMeasuredHeight();
return getScrollY() >= maxScrollHeight;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (contentView == null) {
contentView = getChildAt(0);
}
if (contentView == null) {
Log.e(TAG, "DraggingView has no child view");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
contentView.measure(widthMeasureSpec, 0);
LayoutParams layoutParams = (LayoutParams) contentView.getLayoutParams();
layoutParams.height = contentView.getMeasuredHeight();
//layoutParams.width = contentView.getMeasuredWidth();
contentView.setLayoutParams(layoutParams);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private int minSlideDistance;
private int currY;
private int prevY;
private static final int INVALID_POINTER = -1;
private int pointerIndex = INVALID_POINTER;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
currY = (int) ev.getY();
prevY = (int) ev.getY();
pointerIndex = ev.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
currY = (int) ev.getY();
int scrolledY = prevY - currY;
if (Math.abs(scrolledY) >= minSlideDistance) {
return true;
}
prevY = currY;
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int actionIndex = ev.getActionIndex();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
currY = (int) ev.getY();
prevY = (int) ev.getY();
pointerIndex = ev.getPointerId(0);
break;
case MotionEvent.ACTION_POINTER_DOWN:
pointerIndex = ev.getPointerId(actionIndex);
prevY = (int) (ev.getY(actionIndex));
break;
case MotionEvent.ACTION_MOVE:
final int index = ev.findPointerIndex(pointerIndex);
if (index < 0) {
Log.e(TAG, "pointer index for id " + pointerIndex + " not found.");
return false;
}
currY = (int) ev.getY(index);
int scrolledY = prevY - currY;
//pull down at top
if (childViewReachTop() && scrolledY <= 0) {
double dampingCoefficient = Math.pow(Math.abs(getScrollY()), 1.0 / 4.7);
if (dampingCoefficient == 0) {
dampingCoefficient = 1;
}
this.scrollBy(0, (int) (scrolledY / dampingCoefficient));
}
//pull up at bottom
else if (childViewReachBottom() && scrolledY > 0) {
double dampingCoefficient = Math.pow(Math.abs(getScrollY() - maxScrollHeight), 1.0 / 4.7);
if (dampingCoefficient == 0) {
dampingCoefficient = 1;
}
this.scrollBy(0, (int) (scrolledY / dampingCoefficient));
}
//normal drag
else {
this.scrollBy(0, scrolledY);
}
prevY = currY;
break;
case MotionEvent.ACTION_POINTER_UP:
if (ev.getPointerId(actionIndex) == pointerIndex) {
final int newIndex = actionIndex == 0 ? 1 : 0;
pointerIndex = ev.getPointerId(newIndex);
prevY = (int) ev.getY(newIndex);
}
break;
case MotionEvent.ACTION_UP:
//top rebound
if (childViewReachTop()) {
startScroll(0, getScrollY(), 0, -getScrollY(), 310);
}
//bottom rebound
else if (childViewReachBottom()) {
startScroll(0, getScrollY(), 0, -getScrollY() + maxScrollHeight, 310);
}
//no rebound
else {
//startScroll(0, getScrollY(), 0, -getScrollY(), 310);
}
break;
}
return true;
}
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
scroller.startScroll(startX, startY, dx, dy, duration);
postInvalidate();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
invalidate();
}
}
}
复制代码