package com.tomandjerry.coolanim.lib.pellet; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RadialGradient; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import com.tomandjerry.coolanim.lib.Config; /** * Created by yanxing on 16/1/29. */ public class ForthPellet extends Pellet { // 第一个圆或圆环或圆弧的半径和画笔大小 private float mFiCurR; private float mFiStrokeWidth; // 第二个圆或圆环或圆弧的半径和画笔大小 private float mSeCurR; private float mSeStrokeWidth; // 正常圆(能停留的)最小的直径 private int STANDARD_MIN_R; // 前一个值 private float mPreValue; // 当前值 private float mCurValue; // 差值 private float mDifValue; private Paint mPaint; private int mState = 1; private RectF mRectF; private float mAngle; private float mSweepAngle = 360; // 蓝色弧线的颜色渲染 private SweepGradient mSweepGradient; private AnimatorSet mAnimatorSet; private boolean isStart = false; // private RadialGradient mRadialGradient; // 时间值 private int mDuration1 = 600; private int mDuration2 = 1000; private int mDuration3 = 2000; private int mDuration4 = 1000; private int mDuration5 = 1200; private int mDuration6 = 200; private int mEndCirIRadius; private int mEndCirMRadius; private int mEndCirORadius; private ValueAnimator mEndAnimator; // 正在结束,只绘制结束动画 private boolean isMoveEnd = false; public ForthPellet(int x, int y) { super(x, y); } @Override protected void initConfig() { mEndMovingLength = 145; STANDARD_MIN_R = 15; mFiCurR = MAX_RADIUS_CIRCLE; mFiStrokeWidth = 33; mSeCurR = 0; mSeStrokeWidth = mSeCurR; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); } @Override protected void initAnim() { mAnimatorSet = new AnimatorSet(); // 黄色圆环,内部绿色小球由无变大到圆环,仍然在黄色圆弧内 ValueAnimator anim1 = createInsideCircleAnim(); // 黄色圆环旋转为圆弧,带有一点蓝色的尾巴,逐渐缩短,绿色圆膨胀一些,变为圆环 ValueAnimator anim2 = createRotateAnim(); // 等待小球的到来,黄色圆弧彻底消失,绿色圆弧变为实心圆 ValueAnimator anim3 = createWaitAndFillAnim(); // 填充,等待一会,缩小然后放大 ValueAnimator anim4 = createSmallBiggerAnim(); // 圆环颜色由内向外拓展为蓝色.颜色由浅逐渐变深,一半的时候,内拓为红色,再到黄色,最后全黄,回到第一步 ValueAnimator anim5 = createColorfulAnim(); ValueAnimator anim6 = createPassAnim(); mAnimatorSet.playSequentially(anim1, anim2, anim3, anim4, anim5, anim6 ); mAnimatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { STANDARD_MIN_R = 15; mFiCurR = MAX_RADIUS_CIRCLE; mFiStrokeWidth = 33; mSeCurR = 0; mSeStrokeWidth = mSeCurR; if (mAnimatorStateListen != null) { mAnimatorStateListen.onAnimatorEnd(); } } }); } @Override public void startAnim() { mAnimatorSet.start(); } @Override protected void initEndAnim() { mEndAnimator = ValueAnimator.ofFloat(0, 1, 2).setDuration(mDuration); // mEndAnimator.setRepeatCount(2); mEndAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float zoroToOne = (float) animation.getAnimatedValue(); if (zoroToOne <= 1.0f) { mCurX = (int) (mPerX + zoroToOne * mEndMovingLength); mEndCirIRadius = (int) (MAX_RADIUS_CIRCLE * zoroToOne); if (zoroToOne <= 0.5f) { zoroToOne = 2 * zoroToOne; } else { zoroToOne = 1 - 2 * (zoroToOne - 0.5f); } mEndCirMRadius = (int) (MAX_RADIUS_CIRCLE * zoroToOne); } else { if (!isMoveEnd) { isMoveEnd = true; if (mAnimatorStateListen != null) { mAnimatorStateListen.onMoveEnd(); } } zoroToOne = 2 - zoroToOne; mEndCirIRadius = (int) (MAX_RADIUS_CIRCLE * zoroToOne); if (zoroToOne >= 0.5f) { zoroToOne = (1.0f - zoroToOne) * 2; } else { zoroToOne = zoroToOne * 2; } mEndCirORadius = (int) (MAX_RADIUS_CIRCLE * zoroToOne); } } }); } /** * 第一步:黄色圆环,内部绿色小球由无变大到圆环,仍然在黄色圆弧内 */ public ValueAnimator createInsideCircleAnim() { ValueAnimator anim = ValueAnimator.ofFloat(0, STANDARD_MIN_R, STANDARD_MIN_R + 10); anim.setDuration(mDuration1); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mState = 1; mCurValue = (float) animation.getAnimatedValue(); mDifValue = mCurValue - mPreValue; if (mCurValue <= STANDARD_MIN_R) { // 绿色小球变大 mSeCurR = (float) animation.getAnimatedValue(); mSeStrokeWidth = mSeCurR; } else { // 绿色小球内部变大,成为空心 mSeCurR += mDifValue; mSeStrokeWidth = mSeCurR; // 黄色圆弧变大 mFiCurR -= mDifValue / 2; mFiStrokeWidth -= mDifValue; } mPreValue = mCurValue; } }); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { } }); return anim; } /** * 第二步:黄色圆环旋转为圆弧,带有一点蓝色的尾巴,逐渐缩短,绿色圆膨胀一些,变为圆环 */ protected ValueAnimator createRotateAnim() { // 内部绿色圆膨胀10 final int gap = 10; // 膨胀速率与角度关系 final float rate = gap / 180f; final int[] colors = new int[]{Config.TRANSPARENT, Config.TRANSPARENT, Config.BLUE}; final float[] positions = new float[]{0, 0.8f, 1}; mAngle = 0; mSweepAngle = 360; ValueAnimator animator = ValueAnimator.ofInt(0, 180 + 20); animator.setDuration(mDuration2); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mState = 2; mCurValue = (int) animation.getAnimatedValue(); mDifValue = mCurValue - mPreValue; if (mCurValue <= 180) { mSeCurR += mDifValue * rate / 2; mSeStrokeWidth -= mDifValue * rate; mAngle = mCurValue * 3; mSweepAngle -= mDifValue * 2; } else { mSweepAngle = 0; positions[1] += (mCurValue - 180) * 0.01f; mSweepGradient = new SweepGradient(getCurX(), getCurY(), colors, positions); } mPreValue = mCurValue; } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { // 初始化变量 mCurValue = 0; mPreValue = 0; mSweepAngle = 360; mRectF = new RectF(getCurX() - (MAX_RADIUS_CIRCLE - 5 - mFiStrokeWidth / 2), getCurY() - (MAX_RADIUS_CIRCLE - 5 - mFiStrokeWidth / 2), getCurX() + (MAX_RADIUS_CIRCLE - 5 - mFiStrokeWidth / 2), getCurY() + (MAX_RADIUS_CIRCLE - 5 - mFiStrokeWidth / 2)); colors[2] = Config.BLUE; positions[1] = 0.8f; mSweepGradient = new SweepGradient(getCurX(), getCurY(), colors, positions); } }); return animator; } // 第三步:等待小球的到来,黄色圆弧彻底消失,绿色圆弧变为实心圆 protected ValueAnimator createWaitAndFillAnim() { ValueAnimator animator = ValueAnimator.ofInt(0, 10); animator.setDuration(mDuration3); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { if (!isStart) { return; } mState = 2; mCurValue = (int) animation.getAnimatedValue(); mDifValue = mCurValue - mPreValue; mSeCurR -= mDifValue / 2f; mSeStrokeWidth += mDifValue; mPreValue = mCurValue; } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { isStart = true; mCurValue = 0; mPreValue = 0; } @Override public void onAnimationEnd(Animator animation) { isStart = false; } }); return animator; } // 第四步:填充,等待一会,缩小然后放大 protected ValueAnimator createSmallBiggerAnim() { ValueAnimator animator = ValueAnimator.ofInt(0, STANDARD_MIN_R + MAX_RADIUS_CIRCLE); animator.setDuration(mDuration4); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { if (!isStart) { return; } mState = 2; mCurValue = (int) animation.getAnimatedValue(); mDifValue = mCurValue - mPreValue; if (mCurValue <= STANDARD_MIN_R) { mSeCurR -= mDifValue / 2f; mSeStrokeWidth -= mDifValue / 2f; } else { mSeCurR += mDifValue / 2f; } mPreValue = mCurValue; } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { isStart = true; mCurValue = 0; mPreValue = 0; } @Override public void onAnimationEnd(Animator animation) { isStart = false; } }); return animator; } /** * 第五步:圆环颜色由内向外拓展为蓝色.颜色由浅逐渐变深,一半的时候,内拓为红色,再到黄色,最后全黄,回到第一步 */ protected ValueAnimator createColorfulAnim() { final float[] positions1 = new float[]{0f, 0f, 0f, 0f}; final float[] positions2 = new float[]{0f, 0f, 0f, 0f, 0f, 0f}; final int[] colors1 = new int[]{Config.YELLOW, Config.YELLOW, Config.GREEN, Config.GREEN}; final int[] colors2 = new int[]{Config.YELLOW, Config.YELLOW, Config.RED, Config.RED, Config.BLUE, Config.BLUE}; ValueAnimator animator = ValueAnimator.ofInt(0, 100, 200, 300, 400); animator.setDuration(mDuration5); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { if (!isStart) { return; } mState = 3; mCurValue = (int) animation.getAnimatedValue(); if (mCurValue <= 100) { positions1[0] = 0; positions1[1] = mCurValue / 100f; positions1[2] = positions1[0]; positions1[3] = 1; mRadialGradient = new RadialGradient(getCurX(), getCurY(), mSeCurR + mSeStrokeWidth / 2, colors1, positions1, Shader.TileMode.CLAMP); } else if (mCurValue <= 200) { colors1[0] = Config.BLUE; colors1[1] = Config.BLUE; colors1[2] = Config.YELLOW; colors1[3] = Config.YELLOW; positions1[0] = 0; positions1[1] = (mCurValue - 100) / 100f; positions1[2] = positions1[0]; positions1[3] = 1; mRadialGradient = new RadialGradient(getCurX(), getCurY(), mSeCurR + mSeStrokeWidth / 2, colors1, positions1, Shader.TileMode.CLAMP); } else { positions2[5] = 1; positions2[4] = (mCurValue - 200) / 200f + 0.5f; positions2[3] = positions2[4]; positions2[2] = positions2[3] - 0.2f; positions2[1] = positions2[2]; positions2[0] = 0; mRadialGradient = new RadialGradient(getCurX(), getCurY(), mSeCurR + mSeStrokeWidth / 2, colors2, positions2, Shader.TileMode.CLAMP); } } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mState = 3; isStart = true; mCurValue = 0; mPreValue = 0; positions1[1] = 0f; positions1[0] = 0f; positions2[5] = 0f; positions2[4] = 0f; positions2[3] = 0f; positions2[2] = 0f; positions2[1] = 0f; positions2[0] = 0f; colors1[0] = Config.YELLOW; colors1[1] = Config.YELLOW; colors1[2] = Config.GREEN; colors1[3] = Config.GREEN; mRadialGradient = new RadialGradient(getCurX(), getCurY(), mSeCurR + mSeStrokeWidth, colors1, positions1, Shader.TileMode.CLAMP); } @Override public void onAnimationEnd(Animator animation) { isStart = false; } }); return animator; } /** * 过度动画,使弧线宽度回到初始值 * * @return */ protected ValueAnimator createPassAnim() { final float[] gap = new float[]{0, 0}; ValueAnimator animator = ValueAnimator.ofFloat(0, 1000); animator.setDuration(mDuration6); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { if (!isStart) { return; } mState = 1; mCurValue = (float) animation.getAnimatedValue(); mDifValue = mCurValue - mPreValue; mFiCurR += mDifValue * gap[0]; mFiStrokeWidth += mDifValue * gap[1]; mPreValue = mCurValue; } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mState = 1; isStart = true; mCurValue = 0; mPreValue = 0; mFiCurR = mSeCurR; mFiStrokeWidth = mSeStrokeWidth; gap[0] = (MAX_RADIUS_CIRCLE - mFiCurR) / 1000; gap[1] = (33 - mFiStrokeWidth) / 1000; mSeCurR = 0; mSeStrokeWidth = 0; } @Override public void onAnimationEnd(Animator animation) { isStart = false; } }); return animator; } @Override public void drawSelf(Canvas canvas) { if (!isMoveEnd) { switch (mState) { case 1: // 绘制黄色圆环或圆 mPaint.setStrokeWidth(mFiStrokeWidth); mPaint.setColor(Config.YELLOW); canvas.drawCircle(getCurX(), getCurY(), mFiCurR - mFiStrokeWidth / 2, mPaint); // 绘制绿色圆环 mPaint.setStrokeWidth(mSeStrokeWidth); mPaint.setColor(Config.GREEN); canvas.drawCircle(getCurX(), getCurY(), mSeCurR - mSeStrokeWidth / 2, mPaint); break; case 2: // 绘制蓝色弧线 canvas.save(); canvas.rotate(mAngle - 90, getCurX(), getCurY()); mPaint.setShader(mSweepGradient); canvas.drawCircle(getCurX(), getCurY(), mFiCurR - mFiStrokeWidth / 2, mPaint); canvas.restore(); // 绘制黄色弧线 mPaint.setShader(null); mPaint.setStrokeWidth(mFiStrokeWidth); mPaint.setColor(Config.YELLOW); canvas.drawArc(mRectF, mAngle - 90, mSweepAngle, false, mPaint); // 绘制绿色圆环 mPaint.setStrokeWidth(mSeStrokeWidth); mPaint.setColor(Config.GREEN); canvas.drawCircle(getCurX(), getCurY(), mSeCurR - mSeStrokeWidth / 2, mPaint); break; case 3: // 绘制绿色圆环 mPaint.setStrokeWidth(mSeStrokeWidth); mPaint.setShader(mRadialGradient); canvas.drawCircle(getCurX(), getCurY(), mSeCurR - mSeStrokeWidth / 2, mPaint); mPaint.setShader(null); break; default: break; } } if (mIsEnd) { if (!mIsEndAnimStart) { mEndAnimator.start(); mIsEndAnimStart = true; } mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Config.YELLOW); canvas.drawCircle(getCurX(), getCurY(), mEndCirIRadius, mPaint); mPaint.setColor(Config.BLUE); canvas.drawCircle(getCurX(), getCurY(), mEndCirMRadius, mPaint); mPaint.setColor(Config.GREEN); canvas.drawCircle(getCurX(), getCurY(), mEndCirORadius, mPaint); mPaint.setStyle(Paint.Style.STROKE); return; } } }