package com.roboo.like.netease.view;
import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;
import com.roboo.like.netease.utils.PixelUtils;
/**
* 上下回弹效果的ScrollView
*
* @author MarkMjw
* @date 13-9-12.
*/
public class ReboundScrollView extends ScrollView {
protected Context mContext;
private View mView;
private float mTouchY;
private int mScrollY = 0;
private boolean mHandleStop = false;
private int mEachStep = 0;
/**
* 最大滑动距离
*/
private static final int MAX_SCROLL_HEIGHT = PixelUtils.dp2px(200);
/**
* 阻尼系数,越小阻力就越大
*/
private static final float SCROLL_RATIO = 0.4f;
private Handler mResetPositionHandler = new Handler() {
@Override
public void handleMessage(android.os.Message msg) {
if (mScrollY != 0 && mHandleStop) {
mScrollY -= mEachStep;
if ((mEachStep < 0 && mScrollY > 0) || (mEachStep > 0 && mScrollY < 0)) {
mScrollY = 0;
}
mView.scrollTo(0, mScrollY);
this.sendEmptyMessageDelayed(0, 20);
}
}
};
public ReboundScrollView(Context context) {
super(context);
init(context);
}
public ReboundScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ReboundScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
this.mContext = context;
// 去掉滚动到边界的效果
setOverScrollMode(OVER_SCROLL_NEVER);
}
@Override
protected void onFinishInflate() {
if (getChildCount() > 0) {
this.mView = getChildAt(0);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
mTouchY = arg0.getY();
}
return super.onInterceptTouchEvent(arg0);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mView == null) {
return super.onTouchEvent(ev);
} else {
commonOnTouchEvent(ev);
}
return super.onTouchEvent(ev);
}
private void commonOnTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
if (mView.getScrollY() != 0) {
mHandleStop = true;
animation();
}
break;
case MotionEvent.ACTION_MOVE:
float nowY = ev.getY();
int deltaY = (int) (mTouchY - nowY);
mTouchY = nowY;
if (isNeedMove()) {
int offset = mView.getScrollY();
if (offset < MAX_SCROLL_HEIGHT && offset > -MAX_SCROLL_HEIGHT) {
mView.scrollBy(0, (int) (deltaY * SCROLL_RATIO));
mHandleStop = false;
}
}
break;
default:
break;
}
}
private boolean isNeedMove() {
int viewHeight = mView.getMeasuredHeight();
int scrollHeight = getHeight();
int offset = viewHeight - scrollHeight;
int scrollY = getScrollY();
return scrollY == 0 || scrollY == offset;
}
private void animation() {
mScrollY = mView.getScrollY();
mEachStep = mScrollY / 10;
mResetPositionHandler.sendEmptyMessage(0);
}
}