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.Color; import android.graphics.Paint; import android.graphics.RectF; import com.tomandjerry.coolanim.lib.Config; /** * 用animationset完成 * Created by yanxing on 16/1/29. */ public class ThirdPellet extends Pellet { private Paint mPaint; // 第一个圆或圆环或圆弧的半径和画笔大小 private float mFiCurR; private float mFiStrokeWidth; // 第二个圆或圆环或圆弧的半径和画笔大小 private float mSeCurR; private float mSeStrokeWidth; // 正常圆(能停留的)最大的stroke private float STANDARD_MIN_R; // 前一个值 private float mPreValue; // 当前值 private float mCurValue; // 差值 private float mDifValue; private AnimatorSet mAnimatorSet; //根据状态绘制不同的图案 private int mState; // 用于绘制绿色弧线 private RectF mOval; // 用于绿色弧线的角度 private int mAngle; // 绿色弧线开口的角度 private static final int GAP_ANGLE = 240; private int mGapGreenAngle; // 用于绘制红色弧线 private RectF mRedOval; // 用于绘制红色弧线的角度 private int mRedAngle; // 用于绘制红色弧线的开口角度 private int mGapRedAngle; // 黄色小球,用于弹出 private SmallYellowBall mBall; // private boolean isStart = false; // 时间值 private int mDuration1 = 600; private int mDuration2 = 600; private int mDuration3 = 4000; private int mDuration4 = 800; private int mEndCirIRadius; private int mEndCirMRadius; private int mEndCirORadius; private ValueAnimator mEndAnimator; // 小球移动结束,只绘制结束部分 private boolean isMoveEnd = false; public ThirdPellet(int x, int y) { super(x, y); } @Override protected void initConfig() { mEndMovingLength = -25; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.STROKE); // 初始化黄色小球 mBall = new SmallYellowBall(); mFiCurR = 45; mFiStrokeWidth = 30; mSeCurR = 15; mSeStrokeWidth = 15; STANDARD_MIN_R = 15; } @Override protected void initAnim() { mAnimatorSet = new AnimatorSet(); // 放大弹出射线 // 绿色圆弧包围红色圆,内部先产生间隔,红色圆膨胀,然后绿色圆弧和红色圆膨胀效果 ValueAnimator flattenAnim = createFlattenAnim(); // 等待黄色圆传递 ValueAnimator waitForAnim = ValueAnimator.ofFloat(0, 100); waitForAnim.setDuration(mDuration2); // 黄色圆缩小,绿色弧线出现,旋转从0->-120,从-120->-240,抛出黄色小球,绿色弧线逐渐变成球, // 红色弧线绕圈,逐渐合并为圆环, ValueAnimator smallerAndRotateAnim = createSmallerAndRotateAnim(); // 红色弧线往内缩,绿色圆放大,回到膨胀效果 ValueAnimator backAnim = createBackAnim(); mAnimatorSet.playSequentially(flattenAnim, waitForAnim, smallerAndRotateAnim, backAnim); mAnimatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { 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); } } }); } /** * 红色弧线往内缩,绿色圆放大,回到膨胀效果 * * @return */ protected ValueAnimator createBackAnim() { final float rate = (MAX_RADIUS_CIRCLE - 45) / 30F; ValueAnimator backAnim = ValueAnimator.ofFloat(45, STANDARD_MIN_R); backAnim.setDuration(mDuration4); backAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { if (!isStart) { return; } mState = 4; mCurValue = (float) animation.getAnimatedValue(); mDifValue = mPreValue - mCurValue; // 红色圆弧缩小 mFiStrokeWidth = 15; mFiCurR -= mDifValue * (1 + rate); // 绿色圆放大 mSeStrokeWidth = 30; mSeCurR += mDifValue; mPreValue = mCurValue; } }); backAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { isStart = true; mState = 4; mPreValue = 45; mCurValue = 45; } @Override public void onAnimationEnd(Animator animation) { isStart = false; } }); return backAnim; } /** * 绿色圆弧包围红色圆,内部先产生间隔,红色圆膨胀,然后绿色圆弧和红色圆膨胀效果 * * @return */ protected ValueAnimator createFlattenAnim() { // 产生间隔大小 int gap = 4; // 红色内圆膨胀大小 float redFlattenValue = mFiStrokeWidth - gap - mSeStrokeWidth; // 减去多一个值是因为内圆膨胀的时候,半径也会增加 float bothFlattenValue = MAX_RADIUS_CIRCLE - mSeCurR - redFlattenValue / 2; // 绿色弧放大的速度,红色圆放大速率为1 final float rate = (MAX_RADIUS_CIRCLE - mFiCurR) / bothFlattenValue; // 第一个参数 float fiv = 0; // 第二个参数,外圆内半径扩大距离 final float sev = gap; // 第三个参数,内圆半径扩大,stroke增大的范围 final float thv = sev + redFlattenValue; // 第四个参数,内外圆同时扩大,最后同大小的范围 float fov = thv + bothFlattenValue; ValueAnimator flattenAnim = ValueAnimator.ofFloat(fiv, sev, thv, fov); flattenAnim.setDuration(mDuration1); flattenAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mState = 1; mCurValue = (float) animation.getAnimatedValue(); mDifValue = mCurValue - mPreValue; if (mCurValue <= sev) { // 外圆内半径扩大 mFiStrokeWidth -= mDifValue; mFiCurR += mDifValue / 2; } else if (mCurValue <= thv) { // 内圆半径扩大,stroke增大 mSeStrokeWidth += mDifValue; mSeCurR += mDifValue / 2; } else { // 内外圆同时扩大,最后同大小 mSeCurR += mDifValue; mFiCurR += mDifValue * rate; } mPreValue = mCurValue; } }); flattenAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { mState = 1; mFiCurR = 45; mFiStrokeWidth = 30; mSeCurR = 15; mSeStrokeWidth = 15; // 小球不显示 mBall.setShow(false); } @Override public void onAnimationEnd(Animator animation) { mSeCurR = MAX_RADIUS_CIRCLE; mFiCurR = MAX_RADIUS_CIRCLE; } }); return flattenAnim; } /** * 黄色圆缩小,绿色弧线出现,旋转从0->-120,从-120->-320(此时小球第一次击地,红色圆弧出现),从-320->-120(红色圆弧绕圈) * 抛出黄色小球,绿色弧线逐渐变成球, * 红色弧线绕圈,逐渐合并为圆环, * * @return */ protected ValueAnimator createSmallerAndRotateAnim() { mOval = new RectF(getCurX(), getCurY(), getCurX(), getCurY()); mRedOval = new RectF(getCurX() - MAX_RADIUS_CIRCLE + 5, getCurY() - MAX_RADIUS_CIRCLE + 5, getCurX() + MAX_RADIUS_CIRCLE - 5, getCurY() + MAX_RADIUS_CIRCLE - 5); mAngle = 0; // 绿色弧线默认弧长GAP_ANGLE=240 mGapGreenAngle = GAP_ANGLE; // 根据角度来调整圆大小的缩放比例 final float rate1 = (MAX_RADIUS_CIRCLE - STANDARD_MIN_R) / 120; final float rate2 = (MAX_RADIUS_CIRCLE - STANDARD_MIN_R) / 120; mRedAngle = 60; mGapRedAngle = 0; // 红色弧线开口逐渐合并 final float gapRate = 360 / 420f; // 0->300->420->720 ValueAnimator smallerAnim = ValueAnimator.ofFloat(0, 720); smallerAnim.setDuration(mDuration3); smallerAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { mCurValue = (float) animation.getAnimatedValue(); if (mCurValue <= 120) { // 小黄球缩小 mState = 2; mSeCurR = MAX_RADIUS_CIRCLE - mCurValue * rate1; mSeStrokeWidth = mSeCurR; mDifValue = mCurValue * rate1 + STANDARD_MIN_R - mFiStrokeWidth / 2; mOval.set(getCurX() - mDifValue, getCurY() - mDifValue, getCurX() + mDifValue, getCurY() + mDifValue); } else if (mCurValue < 300) { // 小黄球停留 } else { mState = 3; // 绿色圆弧缩小 mGapGreenAngle = (int) (GAP_ANGLE + mCurValue - 300); if (mCurValue > 300 && mCurValue <= 420) { mDifValue = MAX_RADIUS_CIRCLE - (mCurValue - 300) * rate2 - mFiStrokeWidth / 2; mOval.set(getCurX() - mDifValue, getCurY() - mDifValue, getCurX() + mDifValue, getCurY() + mDifValue); } // 红色弧线开始运动,逐渐合并为圆的状态,从开始到合并为圆弧0->420 mSeStrokeWidth = 12; mGapRedAngle = (int) ((mCurValue - 300) * gapRate); mRedAngle = (int) mCurValue - 240; } if (mCurValue > 300 && mCurValue <= 310) { // 角度为300时, 抛出小黄球, 红色弧线开始运动 mState = 3; if (!mBall.isShow()) { mBall.setCurX(getCurX()); mBall.setCurY(getCurY()); mBall.setShow(true); mBall.throwOut(); } } // 绿色圆弧绕圈 mAngle = -(int) (float) animation.getAnimatedValue(); } }); smallerAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mState = 4; mFiStrokeWidth = 15; mFiCurR = MAX_RADIUS_CIRCLE; mSeStrokeWidth = 30; mSeCurR = 16f; } }); return smallerAnim; } @Override public void drawSelf(Canvas canvas) { if (!isMoveEnd) { switch (mState) { case 1: mPaint.setStrokeWidth(mFiStrokeWidth); mPaint.setColor(Config.GREEN); canvas.drawCircle(getCurX(), getCurY(), mFiCurR - mFiStrokeWidth / 2, mPaint); mPaint.setStrokeWidth(mSeStrokeWidth); mPaint.setColor(Color.RED); canvas.drawCircle(getCurX(), getCurY(), mSeCurR - mSeStrokeWidth / 2, mPaint); break; case 2: mPaint.setColor(Config.GREEN); mPaint.setStrokeWidth(mFiStrokeWidth); canvas.drawArc(mOval, mAngle, GAP_ANGLE, false, mPaint); mPaint.setStrokeWidth(mSeStrokeWidth); mPaint.setColor(Config.YELLOW); canvas.drawCircle(getCurX(), getCurY(), mSeCurR - mSeStrokeWidth / 2, mPaint); break; case 3: // 绘制红色弧线 mPaint.setStrokeWidth(mSeStrokeWidth); mPaint.setColor(Config.RED); canvas.drawArc(mRedOval, mRedAngle, mGapRedAngle, false, mPaint); mPaint.setColor(Config.GREEN); mPaint.setStrokeWidth(mFiStrokeWidth); canvas.drawArc(mOval, mAngle, mGapGreenAngle, false, mPaint); break; case 4: // 绘制绿色圆 mPaint.setStrokeWidth(mSeStrokeWidth); mPaint.setColor(Config.GREEN); canvas.drawCircle(getCurX(), getCurY(), mSeCurR - mSeStrokeWidth / 2, mPaint); // 绘制红色圆弧 mPaint.setStrokeWidth(mFiStrokeWidth); mPaint.setColor(Config.RED); canvas.drawCircle(getCurX(), getCurY(), mFiCurR - mFiStrokeWidth / 2, mPaint); break; default: break; } } if (mIsEnd) { if (!mIsEndAnimStart) { mEndAnimator.start(); mIsEndAnimStart = true; } mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Config.RED); canvas.drawCircle(getCurX(), getCurY(), mEndCirIRadius, mPaint); mPaint.setColor(Config.GREEN); canvas.drawCircle(getCurX(), getCurY(), mEndCirMRadius, mPaint); mPaint.setColor(Config.BLUE); canvas.drawCircle(getCurX(), getCurY(), mEndCirORadius, mPaint); mPaint.setStyle(Paint.Style.STROKE); return; } mBall.drawSelf(canvas); } }