package com.poplar.fancyprogress; import static com.poplar.fancyprogress.utils.Utils.evalute; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.util.AttributeSet; import android.view.View; import android.view.animation.LinearInterpolator; import com.nineoldandroids.animation.ValueAnimator; import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener; public class FancyProgress2 extends View { private static final float mWidth = 100f; private Paint mPaint; public FancyProgress2(Context context) { this(context, null); } public FancyProgress2(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FancyProgress2(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); } private PointF[] mBallCenters = new PointF[]{ new PointF(0, 0), new PointF(mWidth, 0) }; private int[] COLORS = new int[]{ Color.parseColor("#00AAD0"), Color.parseColor("#FD5652") }; private float mRadius = 16f; private float mMaxRadius = 20f; private float mMinRadius = 12f; private float mPercent = 0f; public FancyProgress2 show(){ setVisibility(View.VISIBLE); mAnim = ValueAnimator.ofFloat(1.0f); mAnim.setInterpolator(new LinearInterpolator()); mAnim.setDuration(2000); mAnim.setRepeatCount(ValueAnimator.INFINITE); mAnim.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mPercent = animation.getAnimatedFraction(); isFront = mPercent < 0.5f; invalidate(); } }); mAnim.start(); invalidate(); return this; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int measuredWidth = MeasureSpec.makeMeasureSpec((int)(mRadius * 1.5f * 2f + mWidth), MeasureSpec.EXACTLY); int measuredHeight = MeasureSpec.makeMeasureSpec((int)(mRadius * 1.5f * 2f), MeasureSpec.EXACTLY); setMeasuredDimension(measuredWidth, measuredHeight); } boolean isFront = true; private ValueAnimator mAnim; @Override protected void onDraw(Canvas canvas) { canvas.save(); canvas.translate(mRadius * 1.5f, mRadius* 1.5f); if(isFront){ for (int i = mBallCenters.length - 1; i >= 0 ; i--) { drawBall(canvas, i); } }else { for (int i = 0; i < mBallCenters.length; i++) { drawBall(canvas, i); } } canvas.restore(); } private void drawBall(Canvas canvas, int i) { mPaint.setColor(COLORS[i]); PointF mCurrentCenter = getCurrentCenter(i , mPercent); float mCurrentRadius = getCurrentRadius(i, mPercent, i == 0 ? isFront : !isFront); canvas.drawCircle(mCurrentCenter.x, mCurrentCenter.y, mCurrentRadius, mPaint); } private float getCurrentRadius(int i, float percent, boolean front) { float fraction = percent % 0.5f / 0.5f; // 0f -> 1.0f -> 0f float tempFraction = 1 - Math.abs(fraction - 0.5f) * 2; if(front){ // 放大 return evalute(tempFraction, mRadius, mMaxRadius); }else { // 缩小 return evalute(tempFraction, mRadius, mMinRadius); } } private PointF getCurrentCenter(int i, float percent) { PointF startP = null; PointF endP = null; float fraction = percent % 0.5f / 0.5f; int startOffset = (int) (percent / 0.5f); if(startOffset == 0 && i == 0){ startP = mBallCenters[0]; endP = mBallCenters[1]; }else if (startOffset == 1 && i == 1) { startP = mBallCenters[0]; endP = mBallCenters[1]; }else { startP = mBallCenters[1]; endP = mBallCenters[0]; } return new PointF(evalute(fraction, startP.x, endP.x), evalute(fraction, startP.y, endP.y)); } public void dismiss(){ setVisibility(View.INVISIBLE); if(mAnim != null){ mAnim.end(); } } }