package moe.codeest.enviews;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import com.shuyu.gsyvideoplayer.R;
/**
* Created by codeest on 2016/11/9.
*/
public class ENDownloadView extends View {
public static final int STATE_PRE = 0;
public static final int STATE_DOWNLOADING = 1;
public static final int STATE_END = 2;
public static final int STATE_RESET = 3;
private static final int DEFAULT_LINE_COLOR = Color.WHITE;
private static final int DEFAULT_BG_LINE_COLOR = 0xff3a3f45;
private static final int DEFAULT_TEXT_COLOR = Color.WHITE;
private static final int DEFAULT_LINE_WIDTH = 9;
private static final int DEFAULT_BG_LINE_WIDTH = 9;
private static final int DEFAULT_TEXT_SIZE = 14;
private static final int DEFAULT_STATE = STATE_PRE;
private static final int DEFAULT_RIPPLE_SPEED = 2;
private static final int DEFAULT_DOWNLOAD_TIME = 2000;
private static final DownloadUnit DEFAULT_DOWNLOAD_UNIT = DownloadUnit.B;
private OnDownloadStateListener onDownloadStateListener;
private int mCurrentState;
private float mCurrentRippleX;
private double mCurrentSize, mTotalSize;
private int mTextSize;
private int mDownloadTime;
private DownloadUnit mUnit;
private Paint mPaint, mBgPaint, mTextPaint;
private Path mPath;
private RectF mRectF, mClipRectF;
ValueAnimator mValueAnimator;
private float mFraction;
private float mWidth, mHeight;
private float mCenterX, mCenterY;
private float mBaseLength, mCircleRadius, mBaseRippleLength;
public static enum DownloadUnit {
GB,
MB,
KB,
B,
NONE;
private DownloadUnit() {
}
}
public ENDownloadView(Context context) {
super(context);
}
public ENDownloadView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.download);
int lineColor = ta.getColor(R.styleable.download_download_line_color, DEFAULT_LINE_COLOR);
int bgLineColor = ta.getColor(R.styleable.download_download_bg_line_color, DEFAULT_BG_LINE_COLOR);
int textColor = ta.getColor(R.styleable.download_download_text_color, DEFAULT_TEXT_COLOR);
int lineWidth = ta.getInteger(R.styleable.download_download_line_width, DEFAULT_LINE_WIDTH);
int bgLineWidth = ta.getInteger(R.styleable.download_download_bg_line_width, DEFAULT_BG_LINE_WIDTH);
int textSize = ta.getInteger(R.styleable.download_download_text_size, DEFAULT_TEXT_SIZE);
ta.recycle();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(lineWidth);
mPaint.setColor(lineColor);
mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBgPaint.setStyle(Paint.Style.STROKE);
mBgPaint.setStrokeCap(Paint.Cap.ROUND);
mBgPaint.setStrokeWidth(bgLineWidth);
mBgPaint.setColor(bgLineColor);
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(textColor);
mTextPaint.setTextSize(textSize);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mPath = new Path();
mTextSize = textSize;
mCurrentState = DEFAULT_STATE;
mUnit = DEFAULT_DOWNLOAD_UNIT;
mDownloadTime = DEFAULT_DOWNLOAD_TIME;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
mCenterX = mWidth / 2;
mCenterY = mHeight / 2;
mCircleRadius = mWidth * 5 / 12;
mBaseLength = mCircleRadius / 3;
mBaseRippleLength = 4.4f * mBaseLength / 12;
mCurrentRippleX = mCenterX - mBaseRippleLength * 10;
mRectF = new RectF(mCenterX - mCircleRadius, mCenterY - mCircleRadius, mCenterX + mCircleRadius, mCenterY + mCircleRadius);
mClipRectF = new RectF(mCenterX - 6 * mBaseRippleLength, 0, mCenterX + 6 * mBaseRippleLength, mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (mCurrentState) {
case STATE_PRE:
if (mFraction <= 0.4) {
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mBgPaint);
canvas.drawLine(mCenterX - mBaseLength, mCenterY, mCenterX, mCenterY + mBaseLength, mPaint);
canvas.drawLine(mCenterX, mCenterY + mBaseLength, mCenterX + mBaseLength, mCenterY, mPaint);
canvas.drawLine(mCenterX, mCenterY + mBaseLength - 1.3f * mBaseLength / 0.4f * mFraction,
mCenterX, mCenterY - 1.6f * mBaseLength + 1.3f * mBaseLength / 0.4f * mFraction, mPaint);
} else if (mFraction <= 0.6) {
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mBgPaint);
canvas.drawCircle(mCenterX, mCenterY - 0.3f * mBaseLength, 2, mPaint);
canvas.drawLine(mCenterX - mBaseLength - mBaseLength * 1.2f / 0.2f * (mFraction - 0.4f), mCenterY, mCenterX, mCenterY + mBaseLength - mBaseLength / 0.2f * (mFraction - 0.4f), mPaint);
canvas.drawLine(mCenterX, mCenterY + mBaseLength - mBaseLength / 0.2f * (mFraction - 0.4f), mCenterX + mBaseLength + mBaseLength * 1.2f / 0.2f * (mFraction - 0.4f), mCenterY, mPaint);
} else if (mFraction <= 1) {
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mBgPaint);
canvas.drawCircle(mCenterX, mCenterY - 0.3f * mBaseLength - (mCircleRadius - 0.3f * mBaseLength) / 0.4f * (mFraction - 0.6f), 2, mPaint);
canvas.drawLine(mCenterX - mBaseLength * 2.2f, mCenterY, mCenterX + mBaseLength * 2.2f, mCenterY, mPaint);
} else {
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mBgPaint);
canvas.drawCircle(mCenterX, mCenterY - mCircleRadius - mBaseLength * 3 * (mFraction - 1), 3, mPaint);
canvas.drawLine(mCenterX - mBaseLength * 2.2f, mCenterY, mCenterX + mBaseLength * 2.2f, mCenterY, mPaint);
}
break;
case STATE_DOWNLOADING:
if (mFraction <= 0.2) {
mTextPaint.setTextSize(mTextSize / 0.2f * mFraction);
}
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mBgPaint);
canvas.drawArc(mRectF, -90, 359.99f * mFraction, false, mPaint);
mPath.reset();
mCurrentRippleX += DEFAULT_RIPPLE_SPEED;
if (mCurrentRippleX > mCenterX - mBaseRippleLength * 6)
mCurrentRippleX = mCenterX - mBaseRippleLength * 10;
mPath.moveTo(mCurrentRippleX, mCenterY);
for (int i = 0; i < 4; i++) {
mPath.rQuadTo(mBaseRippleLength, -(1 - mFraction) * mBaseRippleLength, mBaseRippleLength * 2, 0);
mPath.rQuadTo(mBaseRippleLength, (1 - mFraction) * mBaseRippleLength, mBaseRippleLength * 2, 0);
}
canvas.save();
canvas.clipRect(mClipRectF);
canvas.drawPath(mPath, mPaint);
canvas.restore();
if (mUnit != DownloadUnit.NONE && mCurrentSize > 0) {
//canvas.drawText(String.format("%.2f", mCurrentSize) + getUnitStr(mUnit), mCenterX , mCenterY + 1.4f * mBaseLength , mTextPaint);
}
break;
case STATE_END:
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mPaint);
if (mFraction <= 0.5) {
mTextPaint.setTextSize(mTextSize - mTextSize / 0.2f * mFraction);
} else {
mTextPaint.setTextSize(0);
}
if (mUnit != DownloadUnit.NONE && mCurrentSize > 0) {
canvas.drawText(String.format("%.2f", mCurrentSize) + getUnitStr(mUnit), mCenterX, mCenterY + 1.4f * mBaseLength, mTextPaint);
}
canvas.drawLine(mCenterX - mBaseLength * 2.2f + mBaseLength * 1.2f * mFraction, mCenterY,
mCenterX - mBaseLength * 0.5f, mCenterY + mBaseLength * 0.5f * mFraction * 1.3f, mPaint);
canvas.drawLine(mCenterX - mBaseLength * 0.5f, mCenterY + mBaseLength * 0.5f * mFraction * 1.3f,
mCenterX + mBaseLength * 2.2f - mBaseLength * mFraction, mCenterY - mBaseLength * mFraction * 1.3f, mPaint);
break;
case STATE_RESET:
canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mBgPaint);
canvas.drawLine(mCenterX - mBaseLength, mCenterY,
mCenterX - mBaseLength * 0.5f + mBaseLength * 0.5f * mFraction, mCenterY + mBaseLength * 0.65f + mBaseLength * 0.35f * mFraction, mPaint);
canvas.drawLine(mCenterX - mBaseLength * 0.5f + mBaseLength * 0.5f * mFraction, mCenterY + mBaseLength * 0.65f + mBaseLength * 0.35f * mFraction,
mCenterX + mBaseLength * 1.2f - mBaseLength * 0.2f * mFraction, mCenterY - 1.3f * mBaseLength + 1.3f * mBaseLength * mFraction, mPaint);
canvas.drawLine(mCenterX - mBaseLength * 0.5f + mBaseLength * 0.5f * mFraction, mCenterY + mBaseLength * 0.65f + mBaseLength * 0.35f * mFraction,
mCenterX - mBaseLength * 0.5f + mBaseLength * 0.5f * mFraction,
mCenterY + mBaseLength * 0.65f - mBaseLength * 2.25f * mFraction, mPaint);
break;
}
}
public void release() {
if (mValueAnimator != null) {
mValueAnimator.removeAllListeners();
mValueAnimator.removeAllUpdateListeners();
if (mValueAnimator.isRunning())
mValueAnimator.cancel();
mValueAnimator = null;
}
}
public void start() {
if (mValueAnimator != null) {
mValueAnimator.removeAllListeners();
mValueAnimator.removeAllUpdateListeners();
if (mValueAnimator.isRunning())
mValueAnimator.cancel();
mValueAnimator = null;
}
mCurrentState = STATE_DOWNLOADING;
mValueAnimator = ValueAnimator.ofFloat(1.f, 100.f);
mValueAnimator.setDuration(1500);
mValueAnimator.setInterpolator(new OvershootInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mFraction = valueAnimator.getAnimatedFraction();
invalidate();
}
});
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentState = STATE_DOWNLOADING;
downloadAnim();
}
});
mValueAnimator.start();
}
private void downloadAnim() {
if (mValueAnimator != null) {
mValueAnimator.removeAllListeners();
mValueAnimator.removeAllUpdateListeners();
if (mValueAnimator.isRunning())
mValueAnimator.cancel();
mValueAnimator = null;
}
if (mCurrentState != STATE_DOWNLOADING) {
return;
}
mValueAnimator = ValueAnimator.ofFloat(1.f, 100.f);
mValueAnimator.setDuration(mDownloadTime);
mValueAnimator.setInterpolator(new LinearInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mFraction = valueAnimator.getAnimatedFraction();
if (mUnit != DownloadUnit.NONE && mTotalSize > 0)
mCurrentSize = mFraction * mTotalSize;
invalidate();
}
});
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mCurrentState = STATE_DOWNLOADING;
downloadAnim();
}
});
mValueAnimator.start();
}
private void endAnim() {
if (mValueAnimator != null) {
mValueAnimator.removeAllListeners();
mValueAnimator.removeAllUpdateListeners();
if (mValueAnimator.isRunning())
mValueAnimator.cancel();
mValueAnimator = null;
}
mValueAnimator= ValueAnimator.ofFloat(1.f, 100.f);
mValueAnimator.setDuration(700);
mValueAnimator.setInterpolator(new OvershootInterpolator());
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mFraction = valueAnimator.getAnimatedFraction();
invalidate();
}
});
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFraction = 0;
mCurrentState = STATE_RESET;
if (onDownloadStateListener != null) {
onDownloadStateListener.onDownloadFinish();
}
}
});
mValueAnimator.start();
}
public void reset() {
mFraction = 0;
mCurrentState = STATE_PRE;
if (mValueAnimator != null) {
mValueAnimator.removeAllListeners();
mValueAnimator.removeAllUpdateListeners();
if (mValueAnimator.isRunning())
mValueAnimator.cancel();
mValueAnimator = null;
}
}
private String getUnitStr(DownloadUnit unit) {
switch (unit) {
case GB:
return " gb";
case MB:
return " mb";
case KB:
return " kb";
case B:
return " b";
}
return " b";
}
public void setDownloadConfig(int downloadTime, double downloadFileSize, DownloadUnit unit) {
mDownloadTime = downloadTime;
mTotalSize = downloadFileSize;
mUnit = unit;
}
public int getCurrentState() {
return mCurrentState;
}
interface OnDownloadStateListener {
void onDownloadFinish();
void onResetFinish();
}
public void setOnDownloadStateListener(OnDownloadStateListener onDownloadStateListener) {
this.onDownloadStateListener = onDownloadStateListener;
}
}