package com.marshalchen.common.uimodule.simplemodule;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnimationSet;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import com.marshalchen.common.uimodule.widgets.R;
public class DownloadProgressBar extends View {
private static final String TAG = DownloadProgressBar.class.getSimpleName();
private static final int DEFAULT_PROGRESS_DURATION = 1000;
private static final int DEFAULT_RESULT_DURATION = 1000;
private static final float DEFAULT_OVERSHOOT_VALUE = 2.5f;
private Paint mCirclePaint;
private Paint mDrawingPaint;
private Paint mProgressPaint;
private Paint mProgressBackgroundPaint;
private float mRadius;
private float mStrokeWidth;
private float mLineWidth;
private float mArrowLineToDotAnimatedValue;
private float mArrowLineToHorizontalLineAnimatedValue;
private float mDotToProgressAnimatedValue;
private float mCurrentGlobalProgressValue;
private float mSuccessValue;
private float mExpandCollapseValue;
private float mErrorValue;
private float mOvershootValue;
private float mCenterX;
private float mCenterY;
private float mPaddingX;
private float mPaddingY;
private int mCircleBackgroundColor;
private int mDrawingColor;
private int mProgressBackgroundColor;
private int mProgressColor;
private int mProgressDuration;
private int mResultDuration;
private AnimatorSet mArrowToLineAnimatorSet;
private AnimatorSet mProgressAnimationSet;
private OvershootInterpolator mOvershootInterpolator;
private ValueAnimator mDotToProgressAnimation;
private ValueAnimator mProgressAnimation;
private ValueAnimator mSuccessAnimation;
private ValueAnimator mExpandAnimation;
private ValueAnimator mCollapseAnimation;
private ValueAnimator mErrorAnimation;
private ValueAnimator mArrowLineToDot;
private ValueAnimator mArrowLineToHorizontalLine;
private ValueAnimator mManualProgressAnimation;
private RectF mCircleBounds;
private RectF mProgressBackgroundBounds = new RectF();
private RectF mProgressBounds = new RectF();
private OnProgressUpdateListener mOnProgressUpdateListener;
private AnimationSet mAbortAnimationSet;
private AnimatorSet mManualProgressAnimationSet;
private float mFromArc = 0;
private float mToArc = 0;
private float mCurrentGlobalManualProgressValue;
private enum State {ANIMATING_LINE_TO_DOT, IDLE, ANIMATING_SUCCESS, ANIMATING_ERROR, ANIMATING_PROGRESS, ANIMATING_MANUAL_PROGRESS}
private State mState;
private State mResultState;
private State mWhichProgress;
public DownloadProgressBar(Context context) {
super(context);
}
public DownloadProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
initAttrs(context, attrs);
init();
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DownloadProgressView, 0, 0);
try {
mRadius = array.getDimension(R.styleable.DownloadProgressView_dpv_circleRadius, 0);
mStrokeWidth = array.getDimension(R.styleable.DownloadProgressView_dpv_strokeWidth, 0);
mLineWidth = array.getDimension(R.styleable.DownloadProgressView_dpv_lineWidth, 0);
mProgressDuration = array.getInteger(R.styleable.DownloadProgressView_dpv_progressDuration, DEFAULT_PROGRESS_DURATION);
mResultDuration = array.getInteger(R.styleable.DownloadProgressView_dpv_resultDuration, DEFAULT_RESULT_DURATION);
mProgressBackgroundColor = array.getColor(R.styleable.DownloadProgressView_dpv_progressBackgroundColor, 0);
mDrawingColor = array.getColor(R.styleable.DownloadProgressView_dpv_drawingColor, 0);
mProgressColor = array.getColor(R.styleable.DownloadProgressView_dpv_progressColor, 0);
mCircleBackgroundColor = array.getColor(R.styleable.DownloadProgressView_dpv_circleBackgroundColor, 0);
mOvershootValue = array.getFloat(R.styleable.DownloadProgressView_dpv_overshootValue, DEFAULT_OVERSHOOT_VALUE);
} finally {
array.recycle();
}
}
private void init() {
mCirclePaint = new Paint();
mCirclePaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mCirclePaint.setStyle(Paint.Style.STROKE);
mCirclePaint.setColor(mCircleBackgroundColor);
mCirclePaint.setStrokeWidth(mStrokeWidth);
mDrawingPaint = new Paint();
mDrawingPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mDrawingPaint.setStyle(Paint.Style.STROKE);
mDrawingPaint.setColor(mDrawingColor);
mDrawingPaint.setStrokeWidth(mLineWidth);
mProgressPaint = new Paint();
mProgressPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mProgressPaint.setColor(mProgressColor);
mProgressPaint.setStyle(Paint.Style.FILL);
mProgressBackgroundPaint = new Paint();
mProgressBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mProgressBackgroundPaint.setColor(mProgressBackgroundColor);
mProgressBackgroundPaint.setStyle(Paint.Style.FILL);
mState = State.IDLE;
setupAnimations();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCenterX = w / 2f;
mCenterY = h / 2f;
mPaddingX = w / 2f - mRadius;
mPaddingY = h / 2f - mRadius;
mCircleBounds = new RectF();
mCircleBounds.top = mPaddingY;
mCircleBounds.left = mPaddingX;
mCircleBounds.bottom = h / 2f + mRadius;
mCircleBounds.right = w / 2f + mRadius;
}
private void setupAnimations() {
mOvershootInterpolator = new OvershootInterpolator(mOvershootValue);
mArrowLineToDot = ValueAnimator.ofFloat(0, mRadius / 4);
mArrowLineToDot.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mArrowLineToDotAnimatedValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
mArrowLineToDot.setDuration(200);
mArrowLineToDot.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
mState = State.ANIMATING_LINE_TO_DOT;
if (mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onAnimationStarted();
}
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mArrowLineToDot.setInterpolator(new AccelerateInterpolator());
mArrowLineToHorizontalLine = ValueAnimator.ofFloat(0, mRadius / 2);
mArrowLineToHorizontalLine.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mArrowLineToHorizontalLineAnimatedValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
mArrowLineToHorizontalLine.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mArrowLineToHorizontalLine.setDuration(600);
mArrowLineToHorizontalLine.setStartDelay(400);
mArrowLineToHorizontalLine.setInterpolator(mOvershootInterpolator);
mDotToProgressAnimation = ValueAnimator.ofFloat(0, mRadius);
mDotToProgressAnimation.setDuration(600);
mDotToProgressAnimation.setStartDelay(600);
mDotToProgressAnimation.setInterpolator(mOvershootInterpolator);
mDotToProgressAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mDotToProgressAnimatedValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
mDotToProgressAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
if(mWhichProgress == State.ANIMATING_PROGRESS)
mProgressAnimationSet.start();
else if(mWhichProgress == State.ANIMATING_MANUAL_PROGRESS)
mManualProgressAnimationSet.start();
mState = mWhichProgress;
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mArrowToLineAnimatorSet = new AnimatorSet();
mArrowToLineAnimatorSet.playTogether(mArrowLineToDot, mArrowLineToHorizontalLine, mDotToProgressAnimation);
mProgressAnimation = ValueAnimator.ofFloat(0, 360f);
mProgressAnimation.setStartDelay(500);
mProgressAnimation.setInterpolator(new LinearInterpolator());
mProgressAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mCurrentGlobalProgressValue = (float) valueAnimator.getAnimatedValue();
if (mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onProgressUpdate(mCurrentGlobalProgressValue);
}
invalidate();
}
});
mProgressAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
mDotToProgressAnimatedValue = 0;
}
@Override
public void onAnimationEnd(Animator animator) {
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mProgressAnimation.setDuration(mProgressDuration);
mManualProgressAnimation = ValueAnimator.ofFloat(mFromArc, mToArc);
mManualProgressAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mCurrentGlobalManualProgressValue = (float)valueAnimator.getAnimatedValue();
invalidate();
}
});
mManualProgressAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
if(mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onManualProgressStarted();
}
mDotToProgressAnimatedValue = 0;
}
@Override
public void onAnimationEnd(Animator animator) {
if(mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onManualProgressEnded();
}
if(mToArc > 359) {
mCollapseAnimation.start();
}
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mExpandAnimation = ValueAnimator.ofFloat(0, mRadius / 6);
mExpandAnimation.setDuration(300);
mExpandAnimation.setInterpolator(new DecelerateInterpolator());
mExpandAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mExpandCollapseValue = (float) animation.getAnimatedValue();
invalidate();
}
});
mCollapseAnimation = ValueAnimator.ofFloat(mRadius / 6, mStrokeWidth / 2);
mCollapseAnimation.setDuration(300);
mCollapseAnimation.setStartDelay(300);
mCollapseAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
if(mState == State.ANIMATING_MANUAL_PROGRESS) {
if (mResultState == State.ANIMATING_ERROR) {
mErrorAnimation.start();
} else if (mResultState == State.ANIMATING_SUCCESS) {
mSuccessAnimation.start();
}
}
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mCollapseAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
mCollapseAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mExpandCollapseValue = (float) animation.getAnimatedValue();
invalidate();
}
});
mManualProgressAnimationSet = new AnimatorSet();
mManualProgressAnimationSet.playSequentially(mExpandAnimation, mManualProgressAnimation);
mProgressAnimationSet = new AnimatorSet();
mProgressAnimationSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (mResultState == State.ANIMATING_ERROR) {
mErrorAnimation.start();
} else if (mResultState == State.ANIMATING_SUCCESS) {
mSuccessAnimation.start();
}
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mProgressAnimationSet.playSequentially(mExpandAnimation, mProgressAnimation, mCollapseAnimation);
mErrorAnimation = ValueAnimator.ofFloat(0, mRadius / 4);
mErrorAnimation.setDuration(600);
mErrorAnimation.setStartDelay(500);
mErrorAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
mErrorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mErrorValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
mErrorAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
mState = State.ANIMATING_ERROR;
if (mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onAnimationError();
}
}
@Override
public void onAnimationEnd(Animator animator) {
postDelayed(new Runnable() {
@Override
public void run() {
if (mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onAnimationEnded();
}
mState = State.IDLE;
resetValues();
invalidate();
}
}, mResultDuration);
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
mSuccessAnimation = ValueAnimator.ofFloat(0, mRadius / 4);
mSuccessAnimation.setDuration(600);
mSuccessAnimation.setStartDelay(500);
mSuccessAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
mSuccessAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mSuccessValue = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
mSuccessAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
mState = State.ANIMATING_SUCCESS;
if (mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onAnimationSuccess();
}
}
@Override
public void onAnimationEnd(Animator animator) {
postDelayed(new Runnable() {
@Override
public void run() {
if (mOnProgressUpdateListener != null) {
mOnProgressUpdateListener.onAnimationEnded();
}
mState = State.IDLE;
resetValues();
invalidate();
}
}, mResultDuration);
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
}
private void resetValues() {
mArrowLineToDotAnimatedValue = 0;
mArrowLineToHorizontalLineAnimatedValue = 0;
mCurrentGlobalProgressValue = 0;
mCurrentGlobalManualProgressValue = 0;
mManualProgressAnimation.setFloatValues(0,0);
mToArc = 0;
mFromArc = 0;
}
private void drawing(Canvas canvas) {
canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
switch (mState) {
case IDLE:
canvas.drawLine(mCenterX, mCenterY - mRadius / 2, mCenterX, mCenterY + mRadius / 2, mDrawingPaint);
canvas.drawLine(mCenterX - mRadius / 2, mCenterY, mCenterX, mCenterY + mRadius / 2, mDrawingPaint);
canvas.drawLine(mCenterX, mCenterY + mRadius / 2, mCenterX + mRadius / 2, mCenterY, mDrawingPaint);
break;
case ANIMATING_LINE_TO_DOT:
if (!mDotToProgressAnimation.isRunning()) {
canvas.drawLine(
mCenterX,
mCenterY - mRadius / 2 + mArrowLineToDotAnimatedValue * 2 - mStrokeWidth / 2,
mCenterX,
mCenterY + mRadius / 2 - mArrowLineToDotAnimatedValue * 2 + mStrokeWidth / 2,
mDrawingPaint
);
}
canvas.drawLine(
mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2,
mCenterY,
mCenterX,
mCenterY + mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue,
mDrawingPaint
);
canvas.drawLine(
mCenterX,
mCenterY + mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue,
mCenterX + mRadius / 2 + mArrowLineToHorizontalLineAnimatedValue / 2,
mCenterY,
mDrawingPaint
);
break;
case ANIMATING_PROGRESS:
float progress = ((mCenterX + mRadius / 2 + mArrowLineToHorizontalLineAnimatedValue / 2) - (mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2)) / 360f;
mDrawingPaint.setStrokeWidth(mStrokeWidth);
canvas.drawArc(mCircleBounds, -90, mCurrentGlobalProgressValue, false, mDrawingPaint);
mProgressBackgroundBounds.left = mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2;
mProgressBackgroundBounds.top = mCenterY - mExpandCollapseValue;
mProgressBackgroundBounds.right = mCenterX + mRadius / 2 + mArrowLineToHorizontalLineAnimatedValue / 2;
mProgressBackgroundBounds.bottom = mCenterY + mExpandCollapseValue;
canvas.drawRoundRect(mProgressBackgroundBounds, 45, 45, mProgressBackgroundPaint);
mProgressBounds.left = mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2;
mProgressBounds.top = mCenterY - mExpandCollapseValue;
mProgressBounds.right = mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2 + progress * mCurrentGlobalProgressValue;
mProgressBounds.bottom = mCenterY + mExpandCollapseValue;
canvas.drawRoundRect(mProgressBounds, 45, 45, mProgressPaint);
break;
case ANIMATING_MANUAL_PROGRESS:
float manualProgress = ((mCenterX + mRadius / 2 + mArrowLineToHorizontalLineAnimatedValue / 2) - (mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2)) / 360f;
mDrawingPaint.setStrokeWidth(mStrokeWidth);
canvas.drawArc(mCircleBounds, -90, mCurrentGlobalManualProgressValue, false, mDrawingPaint);
mProgressBackgroundBounds.left = mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2;
mProgressBackgroundBounds.top = mCenterY - mExpandCollapseValue;
mProgressBackgroundBounds.right = mCenterX + mRadius / 2 + mArrowLineToHorizontalLineAnimatedValue / 2;
mProgressBackgroundBounds.bottom = mCenterY + mExpandCollapseValue;
canvas.drawRoundRect(mProgressBackgroundBounds, 45, 45, mProgressBackgroundPaint);
mProgressBounds.left = mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2;
mProgressBounds.top = mCenterY - mExpandCollapseValue;
mProgressBounds.right = mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2 + manualProgress * mCurrentGlobalManualProgressValue;
mProgressBounds.bottom = mCenterY + mExpandCollapseValue;
canvas.drawRoundRect(mProgressBounds, 45, 45, mProgressPaint);
break;
case ANIMATING_SUCCESS:
mDrawingPaint.setStrokeWidth(mLineWidth);
canvas.drawArc(mCircleBounds, 0, 360, false, mDrawingPaint);
canvas.drawLine(
mCenterX - mRadius / 2 + mSuccessValue * 2 - mSuccessValue / (float) Math.sqrt(2f) / 2,
mCenterY + mSuccessValue,
mCenterX + mSuccessValue * 2 - mSuccessValue / (float) Math.sqrt(2f) / 2,
mCenterY - mSuccessValue,
mDrawingPaint
);
canvas.drawLine(
mCenterX - mSuccessValue - 2 * mSuccessValue / (float) Math.sqrt(2f) / 2,
mCenterY,
mCenterX + mRadius / 2 - mSuccessValue * 2 - mSuccessValue / (float) Math.sqrt(2f) / 2,
mCenterY + mSuccessValue,
mDrawingPaint
);
break;
case ANIMATING_ERROR:
mDrawingPaint.setStrokeWidth(mLineWidth);
canvas.drawArc(mCircleBounds, 0, 360, false, mDrawingPaint);
canvas.drawLine(
mCenterX - mRadius / 2 - mRadius / 4 + mErrorValue * 2,
mCenterY + mErrorValue,
mCenterX + mErrorValue,
mCenterY - mErrorValue,
mDrawingPaint
);
canvas.drawLine(
mCenterX - mErrorValue,
mCenterY - mErrorValue,
mCenterX + mRadius / 2 + mRadius / 4 - mErrorValue * 2,
mCenterY + mErrorValue,
mDrawingPaint
);
break;
}
if (mDotToProgressAnimatedValue > 0) {
canvas.drawCircle(
mCenterX,
mCenterY - mDotToProgressAnimatedValue,
mStrokeWidth / 2,
mDrawingPaint
);
}
if (mDotToProgressAnimation.isRunning() && !mArrowLineToHorizontalLine.isRunning()) {
canvas.drawLine(
mCenterX - mRadius / 2 - mArrowLineToHorizontalLineAnimatedValue / 2,
mCenterY,
mCenterX + mRadius / 2 + mArrowLineToHorizontalLineAnimatedValue / 2,
mCenterY,
mDrawingPaint
);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawing(canvas);
}
public void playToSuccess() {
mResultState = State.ANIMATING_SUCCESS;
mWhichProgress = State.ANIMATING_PROGRESS;
mArrowToLineAnimatorSet.start();
invalidate();
}
public void playToError() {
mWhichProgress = State.ANIMATING_PROGRESS;
mResultState = State.ANIMATING_ERROR;
mArrowToLineAnimatorSet.start();
invalidate();
}
public void playManualProgressAnimation() {
mWhichProgress = State.ANIMATING_MANUAL_PROGRESS;
mResultState = State.ANIMATING_SUCCESS;
mArrowToLineAnimatorSet.start();
invalidate();
}
public void abortDownload() {
if(mExpandAnimation.isRunning() || mProgressAnimation.isRunning()) {
mProgressAnimationSet.cancel();
mCollapseAnimation.start();
invalidate();
}
}
public void setErrorResultState() {
if(mSuccessAnimation.isRunning() || mErrorAnimation.isRunning())
return;
mResultState = State.ANIMATING_ERROR;
}
public void setSuccessResultState() {
if(mSuccessAnimation.isRunning() || mErrorAnimation.isRunning())
return;
mResultState = State.ANIMATING_SUCCESS;
}
public void setProgress(int value) {
if(value < 1 || value > 100)
return;
mToArc = value * 3.6f;
mManualProgressAnimation.setFloatValues(mFromArc, mToArc);
mManualProgressAnimation.start();
mFromArc = mToArc;
invalidate();
}
public interface OnProgressUpdateListener {
void onProgressUpdate(float currentPlayTime);
void onAnimationStarted();
void onAnimationEnded();
void onAnimationSuccess();
void onAnimationError();
void onManualProgressStarted();
void onManualProgressEnded();
}
public void setOnProgressUpdateListener(OnProgressUpdateListener listener) {
mOnProgressUpdateListener = listener;
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.mState = mState;
savedState.mmCurrentPlayTime = getCurrentPlayTimeByState(mState);
return savedState;
}
private long[] getCurrentPlayTimeByState(State mState) {
long[] tab = new long[3];
switch (mState) {
case ANIMATING_LINE_TO_DOT:
for (int i = 0; i < mArrowToLineAnimatorSet.getChildAnimations().size(); i++) {
tab[i] = ((ValueAnimator) mArrowToLineAnimatorSet.getChildAnimations().get(i)).getCurrentPlayTime();
}
mArrowToLineAnimatorSet.cancel();
break;
case ANIMATING_PROGRESS:
for (int i = 0; i < mProgressAnimationSet.getChildAnimations().size(); i++) {
tab[i] = ((ValueAnimator) mProgressAnimationSet.getChildAnimations().get(i)).getCurrentPlayTime();
}
mProgressAnimationSet.cancel();
break;
case ANIMATING_ERROR:
tab[0] = mErrorAnimation.getCurrentPlayTime();
mErrorAnimation.cancel();
break;
case ANIMATING_SUCCESS:
tab[0] = mSuccessAnimation.getCurrentPlayTime();
mSuccessAnimation.cancel();
break;
}
return tab;
}
private void setCurrentPlayTimeByStateAndPlay(long[] tab, State mState) {
switch (mState) {
case ANIMATING_LINE_TO_DOT:
mArrowToLineAnimatorSet.start();
for (int i = 0; i < mArrowToLineAnimatorSet.getChildAnimations().size(); i++) {
((ValueAnimator) mArrowToLineAnimatorSet.getChildAnimations().get(i)).setCurrentPlayTime(tab[i]);
}
break;
case ANIMATING_PROGRESS:
mProgressAnimationSet.start();
for (int i = 0; i < mProgressAnimationSet.getChildAnimations().size(); i++) {
((ValueAnimator) mProgressAnimationSet.getChildAnimations().get(i)).setCurrentPlayTime(tab[i]);
}
break;
case ANIMATING_ERROR:
mErrorAnimation.start();
mErrorAnimation.setCurrentPlayTime(tab[0]);
break;
case ANIMATING_SUCCESS:
mSuccessAnimation.start();
mSuccessAnimation.setCurrentPlayTime(tab[0]);
break;
}
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof SavedState) {
SavedState savedState = (SavedState) state;
mState = savedState.mState;
super.onRestoreInstanceState(savedState.getSuperState());
if (mState != State.IDLE) {
continueAnimation(mState, savedState.mmCurrentPlayTime);
}
} else {
super.onRestoreInstanceState(state);
}
}
private void continueAnimation(State mState, long[] mmCurrentPlayTime) {
setCurrentPlayTimeByStateAndPlay(mmCurrentPlayTime, mState);
}
static class SavedState extends BaseSavedState {
private boolean isFlashing;
private boolean isConfigurationChanged;
private long[] mmCurrentPlayTime;
private State mState;
public SavedState(Parcel source) {
super(source);
isFlashing = source.readInt() == 1;
isConfigurationChanged = source.readInt() == 1;
mmCurrentPlayTime = source.createLongArray();
}
public SavedState(Parcelable superState) {
super(superState);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(isFlashing ? 1 : 0);
dest.writeInt(isConfigurationChanged ? 1 : 0);
dest.writeLongArray(mmCurrentPlayTime);
}
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
@Override
public SavedState createFromParcel(Parcel source) {
return new SavedState(source);
}
@Override
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}