package com.com.mr_wrong.PullToRefresh;
import android.content.Context;
import android.view.animation.Interpolator;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.BounceInterpolator;
import android.view.animation.Transformation;
import android.widget.ImageView;
import com.Utils.Utils;
/**
* Created by Mr_Wrong on 15/7/11.
*/
public class PullToRefreshView extends ViewGroup {
private final static int DRAG_MAX_DISTANCE = 120;
private View mTarget;
private ImageView mRefreshview;
private int mTotalDragDistance;
private boolean mRefreshing;
private int mTouchSlop;
private int mCurrentOffSetTop;
private boolean mIsBeingDraged;
private float mInitDownY;
private BaseRefreshView mBaseRefreshView;
private int mFrom;
private float mFromDragPercent;
private float mCurrentDragPercent;
private Interpolator mInterpolator;
public PullToRefreshView(Context context) {
this(context, null);
}
public PullToRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
mRefreshview = new ImageView(context);
mInterpolator = new BounceInterpolator();
mBaseRefreshView = new SunRefreshView(getContext(), this);
mRefreshview.setImageDrawable(mBaseRefreshView);
addView(mRefreshview);
mTotalDragDistance = Utils.dip2px(context, DRAG_MAX_DISTANCE);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
setWillNotDraw(false);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
ensureTarget();
widthMeasureSpec = MeasureSpec.makeMeasureSpec(getWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(getHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY);
mTarget.measure(widthMeasureSpec, heightMeasureSpec);
mRefreshview.measure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 获取child
*/
private void ensureTarget() {
if (mTarget != null)
return;
if (getChildCount() > 0) {
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child != mRefreshview)
mTarget = child;
}
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!isEnabled() || mRefreshing) {
return false;
}
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
mRefreshing = false;
setTargetOffsetTop(0);
mIsBeingDraged = false;
mInitDownY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float yd = ev.getY() - mInitDownY;
if (yd > mTouchSlop && !mIsBeingDraged) {
mIsBeingDraged = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsBeingDraged = false;
break;
}
return mIsBeingDraged;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!mIsBeingDraged) {
return super.onTouchEvent(event);
}
final int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_MOVE:
final float y = event.getY();
final float yDiff = y - mInitDownY;//手指移动距离
final float scrollTop = yDiff * 0.5f;//*0.5
mCurrentDragPercent = scrollTop / mTotalDragDistance;
//Log.e("mTotalDragDistance----", mTotalDragDistance+"");//330
if (mCurrentDragPercent < 0) {
return false;
}
float boundedDragPercent = Math.min(1f, Math.abs(mCurrentDragPercent));
// LogUtils.e(boundedDragPercent);//0-1
float extraOS = Math.abs(scrollTop) - mTotalDragDistance;
//LogUtils.e(extraOS);//-330-+300+
float slingshotDist = mTotalDragDistance;//330弹弓
float tensionSlingshotPercent = Math.max(0, extraOS / 330);//张力弹弓
//Log.e("tensionSlingshotPercent----", tensionSlingshotPercent+"");//0-0.23....
float tensionPercent = (float) ((tensionSlingshotPercent / 4) -
Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;
//Log.e("tensionPercent----", tensionPercent+"");//0-0.24...
float extraMove = (slingshotDist) * tensionPercent / 2;
int targetY = (int) ((slingshotDist * boundedDragPercent) + extraMove);
//LogUtils.e(targetY);//0-330+
//Log.e("mCurrentDragPercent----", mCurrentDragPercent+"");//0-0.24...
mBaseRefreshView.setPercent(mCurrentDragPercent, true);//在这里将百分比穿进去的啊
//Log.e("targetY - mCurrentOffsetTop----", targetY - mCurrentOffsetTop+"");//很小整数
setTargetOffsetTop(targetY - mCurrentOffSetTop);//如果注释,向下滑动list没反应,targetY - mCurrentOffsetTop一直变大
break;
case MotionEvent.ACTION_UP:
animateOffsetToStartPosition();
break;
}
return true;
}
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
ensureTarget();
int height = getMeasuredHeight();
int width = getMeasuredWidth();
int left = getPaddingLeft();
int top = getPaddingTop();
int right = getPaddingRight();
int bottom = getPaddingBottom();
mRefreshview.layout(left, top, left + width - right, top + height - bottom);
mTarget.layout(left, top + mCurrentOffSetTop, left + width - right, top + mCurrentOffSetTop + height - bottom);
}
/**
* 设置offset
*
* @param OffsetTop
*/
public void setTargetOffsetTop(int OffsetTop) {
//LogUtils.e(OffsetTop);//向下就是正,向上就是负
mTarget.offsetTopAndBottom(OffsetTop);//相对的移动距离
mBaseRefreshView.offsetTopAndBottom(OffsetTop);
mCurrentOffSetTop = mTarget.getTop();
invalidate();
}
public int getTotalDragDistance() {
return mTotalDragDistance;
}
/**
* 滚动到起始位置
*/
private void animateOffsetToStartPosition() {
mFrom = mCurrentOffSetTop;
//Log.e("mFrom-====", mFrom+"");330
mFromDragPercent = mCurrentDragPercent;
long animationDuration = Math.abs((long) (700 * mFromDragPercent));
mAnimateToStartPosition.reset();
mAnimateToStartPosition.setDuration(animationDuration);
mAnimateToStartPosition.setInterpolator(mInterpolator);
mAnimateToStartPosition.setAnimationListener(mToStartListener);
mRefreshview.clearAnimation();
mRefreshview.startAnimation(mAnimateToStartPosition);
}
private final Animation mAnimateToStartPosition = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
//Log.e("mAnimateToStartPosition----interpolatedTime", interpolatedTime+"");
moveToStart(interpolatedTime);
}
};
private void moveToStart(float interpolatedTime) {
int targetTop = mFrom - (int) (mFrom * interpolatedTime);
float targetPercent = mFromDragPercent * (1.0f - interpolatedTime);
int offset = targetTop - mTarget.getTop();
mCurrentDragPercent = targetPercent;
mBaseRefreshView.setPercent(mCurrentDragPercent, true);
setTargetOffsetTop(offset);
}
private Animation.AnimationListener mToStartListener = new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
mBaseRefreshView.stop();
mCurrentOffSetTop = mTarget.getTop();
}
};
}