[转载]一款Android开源的下拉刷新动画 - 有梦想的小人物 - 博客园

[转载]一款Android开源的下拉刷新动画 – 有梦想的小人物 – 博客园.

无意间在GitHub看到的,就Down了下来。但是作者是用AndroidStudio开发的,这边移动Eclipse供小伙伴们下载使用。

截图

这么好的东西因为字数不够不让分享,得了,贴段代码吧

package com.example.pullrefersh;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
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.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.Transformation;
import android.widget.AbsListView;
import android.widget.ImageView;

import java.security.InvalidParameterException;

import refresh_view.BaseRefreshView;
import refresh_view.SunRefreshView;
import util.Utils;

public class PullToRefreshView extends ViewGroup {

private static final int DRAG_MAX_DISTANCE = 120;
private static final float DRAG_RATE = .5f;
private static final float DECELERATE_INTERPOLATION_FACTOR = 2f;

public static final int STYLE_SUN = 0;
public static final int STYLE_JET = 1;
public static final int MAX_OFFSET_ANIMATION_DURATION = 700;

private static final int INVALID_POINTER = -1;

private View mTarget;
private ImageView mRefreshView;
private Interpolator mDecelerateInterpolator;
private int mTouchSlop;
private int mTotalDragDistance;
private BaseRefreshView mBaseRefreshView;
private float mCurrentDragPercent;
private int mCurrentOffsetTop;
private boolean mRefreshing;
private int mActivePointerId;
private boolean mIsBeingDragged;
private float mInitialMotionY;
private int mFrom;
private float mFromDragPercent;
private boolean mNotify;
private OnRefreshListener mListener;

public PullToRefreshView(Context context) {
this(context, null);
}

public PullToRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RefreshView);
final int type = a.getInteger(R.styleable.RefreshView_type, STYLE_SUN);
a.recycle();

mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mTotalDragDistance = Utils.convertDpToPixel(context, DRAG_MAX_DISTANCE);

mRefreshView = new ImageView(context);

setRefreshStyle(type);

addView(mRefreshView);

setWillNotDraw(false);
// ViewCompat.setChildrenDrawingOrderEnabled(this, true);
}

public void setRefreshStyle(int type) {
setRefreshing(false);
switch (type) {
case STYLE_SUN:
mBaseRefreshView = new SunRefreshView(getContext(), this);
break;
case STYLE_JET:
// TODO
default:
throw new InvalidParameterException("Type does not exist");
}
mRefreshView.setImageDrawable(mBaseRefreshView);
}

public int getTotalDragDistance() {
return mTotalDragDistance;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

ensureTarget();
if (mTarget == null)
return;

widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingRight() - getPaddingLeft(), MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY);
mTarget.measure(widthMeasureSpec, heightMeasureSpec);
mRefreshView.measure(widthMeasureSpec, heightMeasureSpec);
}

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() || canChildScrollUp() || mRefreshing) { return false; } final int action = MotionEventCompat.getActionMasked(ev); switch (action) { case MotionEvent.ACTION_DOWN: setTargetOffsetTop(0, true); mActivePointerId = MotionEventCompat.getPointerId(ev, 0); mIsBeingDragged = false; final float initialMotionY = getMotionEventY(ev, mActivePointerId); if (initialMotionY == -1) { return false; } mInitialMotionY = initialMotionY; break; case MotionEvent.ACTION_MOVE: if (mActivePointerId == INVALID_POINTER) { return false; } final float y = getMotionEventY(ev, mActivePointerId); if (y == -1) { return false; } final float yDiff = y - mInitialMotionY; if (yDiff > mTouchSlop && !mIsBeingDragged) {
mIsBeingDragged = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mIsBeingDragged = false;
mActivePointerId = INVALID_POINTER;
break;
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}

return mIsBeingDragged;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {

if (!mIsBeingDragged) {
return super.onTouchEvent(ev);
}

final int action = MotionEventCompat.getActionMasked(ev);

switch (action) {
case MotionEvent.ACTION_MOVE: {
final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
if (pointerIndex < 0) {
return false;
}

final float y = MotionEventCompat.getY(ev, pointerIndex);
final float yDiff = y - mInitialMotionY;
final float scrollTop = yDiff * DRAG_RATE;
mCurrentDragPercent = scrollTop / mTotalDragDistance;
if (mCurrentDragPercent < 0) { return false; } float boundedDragPercent = Math.min(1f, Math.abs(mCurrentDragPercent)); float extraOS = Math.abs(scrollTop) - mTotalDragDistance; float slingshotDist = mTotalDragDistance; float tensionSlingshotPercent = Math.max(0, Math.min(extraOS, slingshotDist * 2) / slingshotDist); float tensionPercent = (float) ((tensionSlingshotPercent / 4) - Math.pow( (tensionSlingshotPercent / 4), 2)) * 2f; float extraMove = (slingshotDist) * tensionPercent / 2; int targetY = (int) ((slingshotDist * boundedDragPercent) + extraMove); mBaseRefreshView.setPercent(mCurrentDragPercent, true); setTargetOffsetTop(targetY - mCurrentOffsetTop, true); break; } case MotionEventCompat.ACTION_POINTER_DOWN: final int index = MotionEventCompat.getActionIndex(ev); mActivePointerId = MotionEventCompat.getPointerId(ev, index); break; case MotionEventCompat.ACTION_POINTER_UP: onSecondaryPointerUp(ev); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { if (mActivePointerId == INVALID_POINTER) { return false; } final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); final float y = MotionEventCompat.getY(ev, pointerIndex); final float overScrollTop = (y - mInitialMotionY) * DRAG_RATE; mIsBeingDragged = false; if (overScrollTop > mTotalDragDistance) {
setRefreshing(true, true);
} else {
mRefreshing = false;
animateOffsetToStartPosition();
}
mActivePointerId = INVALID_POINTER;
return false;
}
}

return true;
}

private void animateOffsetToStartPosition() {
mFrom = mCurrentOffsetTop;
mFromDragPercent = mCurrentDragPercent;
long animationDuration = Math.abs((long) (MAX_OFFSET_ANIMATION_DURATION * mFromDragPercent));

mAnimateToStartPosition.reset();
mAnimateToStartPosition.setDuration(animationDuration);
mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
mAnimateToStartPosition.setAnimationListener(mToStartListener);
mRefreshView.clearAnimation();
mRefreshView.startAnimation(mAnimateToStartPosition);
}

private void animateOffsetToCorrectPosition() {
mFrom = mCurrentOffsetTop;
mFromDragPercent = mCurrentDragPercent;

mAnimateToCorrectPosition.reset();
mAnimateToCorrectPosition.setDuration(MAX_OFFSET_ANIMATION_DURATION);
mAnimateToCorrectPosition.setInterpolator(mDecelerateInterpolator);
mRefreshView.clearAnimation();
mRefreshView.startAnimation(mAnimateToCorrectPosition);

if (mRefreshing) {
mBaseRefreshView.start();
if (mNotify) {
if (mListener != null) {
mListener.onRefresh();
}
}
} else {
mBaseRefreshView.stop();
animateOffsetToStartPosition();
}
mCurrentOffsetTop = mTarget.getTop();
}

private final Animation mAnimateToStartPosition = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
moveToStart(interpolatedTime);
}
};

private final Animation mAnimateToCorrectPosition = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
int targetTop;
int endTarget = mTotalDragDistance;
targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
int offset = targetTop - mTarget.getTop();

mCurrentDragPercent = mFromDragPercent - (mFromDragPercent - 1.0f) * interpolatedTime;
mBaseRefreshView.setPercent(mCurrentDragPercent, false);

setTargetOffsetTop(offset, false /* requires update */);
}
};

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, false);
}

public void setRefreshing(boolean refreshing) {
if (mRefreshing != refreshing) {
setRefreshing(refreshing, false /* notify */);
}
}

private void setRefreshing(boolean refreshing, final boolean notify) {
if (mRefreshing != refreshing) {
mNotify = notify;
ensureTarget();
mRefreshing = refreshing;
if (mRefreshing) {
mBaseRefreshView.setPercent(1f, true);
animateOffsetToCorrectPosition();
} else {
animateOffsetToStartPosition();
}
}
}

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();
}
};

private void onSecondaryPointerUp(MotionEvent ev) {
final int pointerIndex = MotionEventCompat.getActionIndex(ev);
final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
if (pointerId == mActivePointerId) {
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
}
}

private float getMotionEventY(MotionEvent ev, int activePointerId) {
final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
if (index < 0) {
return -1;
}
return MotionEventCompat.getY(ev, index);
}

private void setTargetOffsetTop(int offset, boolean requiresUpdate) {
mTarget.offsetTopAndBottom(offset);
mBaseRefreshView.offsetTopAndBottom(offset);
mCurrentOffsetTop = mTarget.getTop();
if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
invalidate();
}
}

private boolean canChildScrollUp() {
if (android.os.Build.VERSION.SDK_INT < 14) { if (mTarget instanceof AbsListView) { final AbsListView absListView = (AbsListView) mTarget; return absListView.getChildCount() > 0
&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
.getTop() < absListView.getPaddingTop()); } else { return mTarget.getScrollY() > 0;
}
} else {
return ViewCompat.canScrollVertically(mTarget, -1);
}
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

ensureTarget();
if (mTarget == null)
return;

int height = getMeasuredHeight();
int width = getMeasuredWidth();
int left = getPaddingLeft();
int top = getPaddingTop();
int right = getPaddingRight();
int bottom = getPaddingBottom();

mTarget.layout(left, top + mCurrentOffsetTop, left + width - right, top + height - bottom + mCurrentOffsetTop);
mRefreshView.layout(left, top, left + width - right, top + height - bottom);
}

public void setOnRefreshListener(OnRefreshListener listener) {
mListener = listener;
}

public static interface OnRefreshListener {
public void onRefresh();
}

}

下载地址:http://download.csdn.net/detail/lj419855402/8421179

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏