自定义view超萌小炸弹

BombView:

package com.example.a08_bomb;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

/**
 * Created by yujie on 2017/12/6.
 */

public class BombView extends View {
    private Paint mPaint;
    private Path mPath, mHeadLinePath ,mHeadPath ,mBodyLightPath;
    private int bombColor = Color.parseColor("#88B0E8");
    private int bombLineColor = Color.parseColor("#181D82");
    private int bombShadowColor = Color.parseColor("#77609ee6");
    private int lightColor = Color.WHITE;
    private int bombLineWidth;
    //炸弹身体半径 高光半径
    private int bodyRadius, highLightRadius;
    //用于处理线条的分割点
    private DashPathEffect groundDashPathEffect,bodyDashPathEffect,highLightPathEffect,mHeadEffect;
    private RectF mRectF;
    private PathMeasure mPathMeasure=new PathMeasure();
    private float[] mPathPosition=new float[2];
    //动画控制相关
    private float faceLROffset , faceMaxLROffset;
    private float faceTBOffset =0, faceMaxTBOffset;
    private float bombLRRotate =15, bombMaxLRRotate =15 ,bombTBRotate=0, bombMaxTBRotate =5;
    private float eyeRadius,eyeMaxRadius,eyeMinRadius;
    private float headLinePercent=1,headLineLightRate=0;
    private float maxBlastCircleRadius, currentBlastCircleRadius,blastCircleRadiusPercent;
    //用于计算mouth第二阶段变化
    private float mouthMaxWidthOffset, mouthMaxHeightOffset, mouthWidthOffset=0, mouthHeightOffset =0,mouthOffsetPercent=0;
    //用于计算mouth第一阶段变化
    private float mouthFSMaxWidthOffset,mouthFSMaxHeightOffset,mouthFSWidthOffset=0,mouthFSHeightOffset=0;
    //炸弹的中心点
    private int bombCenterX,bombCenterY;
    //用于控制旋转
    private Camera mCamera=new Camera();
    private Matrix mMatrix=new Matrix();


    public BombView(Context context) {
        super(context);
        init();
    }

    public BombView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BombView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public BombView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width=getMeasuredWidth();
        int height=getMeasuredHeight();
        int minLength= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,100,getContext().getResources().getDisplayMetrics());
        minLength=Math.max(Math.min(width,height),minLength);
        setMeasuredDimension(minLength,minLength);
    }

    private void init() {
        mPaint=new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPath=new Path();
        mRectF=new RectF();
        mHeadLinePath =new Path();
        mHeadPath =new Path();
        mBodyLightPath =new Path();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        bombLineWidth =getMeasuredWidth()/35;
        mPaint.setStrokeWidth(bombLineWidth);
        float[] groundEffectFloat=new float[]{bombLineWidth/4,bombLineWidth/2+bombLineWidth,bombLineWidth*2,bombLineWidth/3*2+bombLineWidth,getMeasuredWidth(),0};
        groundDashPathEffect=new DashPathEffect(groundEffectFloat,0);
        bodyRadius= (int) (getMeasuredHeight()/3.4f);
        float[] bodyEffectFloat=new float[]{getRadianLength(56,bodyRadius)
                ,getRadianLength(4,bodyRadius)+bombLineWidth
                ,getRadianLength(2.5f,bodyRadius)
                ,getRadianLength(4,bodyRadius)+bombLineWidth
                ,getRadianLength(220,bodyRadius)
                ,getRadianLength(12,bodyRadius)+bombLineWidth
                ,getRadianLength(90,bodyRadius)
                ,0};
        bodyDashPathEffect=new DashPathEffect(bodyEffectFloat,0);

        highLightRadius =bodyRadius/3*2;
        float[] highLightFloat=new float[]{0,getRadianLength(95, highLightRadius)
                ,getRadianLength(0.5f, highLightRadius)
                ,getRadianLength(5, highLightRadius)+bombLineWidth
                ,getRadianLength(12, highLightRadius)
                ,getRadianLength(5, highLightRadius)+bombLineWidth
                ,getRadianLength(24, highLightRadius)
                ,getRadianLength(270, highLightRadius)};
        highLightPathEffect=new DashPathEffect(highLightFloat,0);

        float padding= (float) (2*bombLineWidth*Math.PI/2/72);
        mHeadEffect=new DashPathEffect(new float[]{padding*2,padding},0);

        faceMaxLROffset =bodyRadius/3;
        faceLROffset =-faceMaxLROffset;
        eyeRadius=eyeMaxRadius=bombLineWidth/2;
        eyeMinRadius=eyeMaxRadius/6;

        faceMaxTBOffset=bodyRadius/3;
        maxBlastCircleRadius = getMeasuredWidth()*(2);

        mouthMaxWidthOffset =bodyRadius/5-bodyRadius/5/10;
        mouthMaxHeightOffset =bodyRadius/5/2;

        mouthFSMaxWidthOffset= mouthMaxWidthOffset/3;
        mouthFSMaxHeightOffset = mouthMaxHeightOffset/2;

        bombCenterX=getMeasuredWidth()/2;
        bombCenterY=getMeasuredHeight()-bombLineWidth-bodyRadius;

        setHeadLinePath();
        setHeadPath();
        setBodyLightPath();
    }

    private void setBodyLightPath() {
        //160度坐标计算
        mBodyLightPath.reset();
        Point point=getPointInCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth,160);
        mBodyLightPath.moveTo(point.x-bodyRadius,point.y);
        mBodyLightPath.lineTo(point.x,point.y);
        Point pointControl=getPointInCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth+bombLineWidth*2.2f,210);
        point=getPointInCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth,260);
        mBodyLightPath.quadTo(pointControl.x,pointControl.y,point.x,point.y);
        mBodyLightPath.lineTo(point.x-bodyRadius,point.y);
        mBodyLightPath.close();
    }

    private void setHeadPath() {
        mHeadPath.reset();
        mHeadPath.moveTo(bombCenterX-bodyRadius/5,getMeasuredHeight()/2);
        mHeadPath.lineTo(bombCenterX+bodyRadius/5,getMeasuredHeight()/2);
        mHeadPath.lineTo(bombCenterX+bodyRadius/5,bombCenterY-bodyRadius-bodyRadius/4);
        mHeadPath.lineTo(bombCenterX,bombCenterY-bodyRadius-bodyRadius/4-bodyRadius/4/4);
        mHeadPath.lineTo(bombCenterX-bodyRadius/5,bombCenterY-bodyRadius-bodyRadius/4);
        mHeadPath.close();
    }

    private void setHeadLinePath() {
        float beginY=bombCenterY-bodyRadius-bodyRadius/4-bodyRadius/4/4;
        mHeadLinePath.reset();
        mHeadLinePath.moveTo(bombCenterX,beginY);
        float controlY=beginY-bodyRadius/2.2f;
        float bottomPointY=bombCenterY-bodyRadius;//转折点高度
        mHeadLinePath.quadTo(bombCenterX+bodyRadius/2/5,controlY,bombCenterX+bodyRadius/2,controlY);
        mHeadLinePath.cubicTo(bombCenterX+bodyRadius/2+bodyRadius/2/5*4,controlY
                ,bombCenterX+bodyRadius/2*2f-bodyRadius/16,bottomPointY-bodyRadius/6
                ,bombCenterX+bodyRadius/2*2f,bottomPointY);
        mHeadLinePath.quadTo(bombCenterX+bodyRadius/2*2f+bodyRadius/16,bottomPointY+bodyRadius/6
                ,bombCenterX+bodyRadius/2*2f+bodyRadius/7,bottomPointY+bodyRadius/4);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawHead(canvas);//头部小房子
        drawGround(canvas);//地板
        drawBody(canvas);//身体
        drawBodyBorder(canvas);//身体边框
        drawFace(canvas);//脸
        drawFaceShadow(canvas);//脸阴影
        drawHeadLine(canvas);//头部的炸弹线
        drawBlast(canvas);//爆炸
    }

    private void drawFaceShadow(Canvas canvas) {
        //两个圆相交产生阴影
        int save=canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(bombShadowColor);
        canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        canvas.translate(-bodyRadius/5,-bodyRadius/5);
        mPaint.setColor(bombColor);
        canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
        canvas.restoreToCount(save);
        mPaint.setXfermode(null);
    }

    private void drawFace(Canvas canvas) {
        canvas.save();
        mCamera.save();
        mCamera.rotate(bombTBRotate,0,-bombLRRotate/3);
        mMatrix.reset();
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-bombCenterX,-(bombCenterY));
        mMatrix.postTranslate(bombCenterX,bombCenterY);
        mMatrix.postTranslate(faceLROffset,faceTBOffset);
        canvas.concat(mMatrix);
        //眼睛 椭圆控制
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(bombLineColor);
        float eyeY=bombCenterY+bodyRadius/5;
        float eyeWidth=Math.max(eyeMaxRadius,eyeRadius);
        mRectF.set(bombCenterX-bodyRadius/3.5f-eyeWidth,eyeY-eyeRadius
                ,bombCenterX-bodyRadius/3.5f+eyeWidth,eyeY+eyeRadius);
        canvas.drawOval(mRectF,mPaint);
        mRectF.set(bombCenterX+bodyRadius/3.5f-eyeWidth,eyeY-eyeRadius
                ,bombCenterX+bodyRadius/3.5f+eyeWidth,eyeY+eyeRadius);
        canvas.drawOval(mRectF,mPaint);
        //画嘴巴 路径
        float mouthY=eyeY+bombLineWidth- mouthHeightOffset;//嘴巴起始高度
        float mouthMaxY=mouthY+bodyRadius/7+ mouthHeightOffset - mouthFSHeightOffset;//嘴巴最底部
        float mouthHalfDistance=bodyRadius/5-mouthWidthOffset*0.5f + mouthFSWidthOffset;//嘴巴顶部的拐角的一半宽度
        float mouthTopHalfDistance=(mouthHalfDistance-bodyRadius/5/10)-mouthWidthOffset; //嘴巴顶部的一半宽度
        float mouthHorDistanceHalf=(mouthMaxY-mouthY)/(6-4*mouthOffsetPercent);//嘴角控制点的距离嘴角点的竖直距离
        if (mouthTopHalfDistance<bodyRadius/5/10){//让过渡更加自然
            mouthTopHalfDistance=0;
        }
        mPath.reset();
        mPath.moveTo(bombCenterX-mouthTopHalfDistance,mouthY);
        mPath.lineTo(bombCenterX+mouthTopHalfDistance,mouthY);

        mPath.quadTo(bombCenterX+mouthHalfDistance,mouthY,
                bombCenterX+mouthHalfDistance,mouthY+mouthHorDistanceHalf);
        mPath.cubicTo(bombCenterX+mouthHalfDistance,mouthY+mouthHorDistanceHalf*2,
                bombCenterX+(mouthHalfDistance-bodyRadius/5/4)*(1-mouthOffsetPercent),mouthMaxY,
                bombCenterX,mouthMaxY);

        mPath.cubicTo(bombCenterX-(mouthHalfDistance-bodyRadius/5/4)*(1-mouthOffsetPercent),mouthMaxY,
                bombCenterX-mouthHalfDistance,mouthY+mouthHorDistanceHalf*2,
                bombCenterX-mouthHalfDistance,mouthY+mouthHorDistanceHalf);
        mPath.quadTo(bombCenterX-mouthHalfDistance,mouthY,bombCenterX-mouthTopHalfDistance,mouthY);
        mPath.close();
        canvas.drawPath(mPath,mPaint);
        //画舌头 圆和嘴巴的缩放相交
        int save=canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
        canvas.drawPath(mPath,mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        mPaint.setColor(Color.parseColor("#f34671"));
        canvas.drawCircle(bombCenterX,mouthY+(mouthMaxY-mouthY)/8+bodyRadius/(5-1.4f*mouthOffsetPercent),bodyRadius/5,mPaint);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        canvas.scale(0.8f,0.8f,bombCenterX,(mouthMaxY+mouthY)/2);
        canvas.drawPath(mPath,mPaint);
        canvas.restoreToCount(save);
        mPaint.setXfermode(null);
        //酒窝
        mPaint.setColor(Color.parseColor("#5689cc"));
        canvas.drawCircle(bombCenterX-bodyRadius/3.5f-bombLineWidth,(mouthMaxY+mouthY)/2,bombLineWidth/3,mPaint);
        canvas.drawCircle(bombCenterX+bodyRadius/3.5f+bombLineWidth,(mouthMaxY+mouthY)/2,bombLineWidth/3,mPaint);
        mPaint.setPathEffect(null);
        canvas.restore();
    }

    private void drawBlast(Canvas canvas) {
        if (blastCircleRadiusPercent==0){
            return;
        }
        float circleY=bombCenterY-bodyRadius-bodyRadius/4-bodyRadius/4/4;
        int save = canvas.saveLayer(0,0,getMeasuredWidth(),getMeasuredHeight(),null,Canvas.ALL_SAVE_FLAG);
        float distance = maxBlastCircleRadius/12;
        //画圆
        mPaint.setColor(lightColor);
        canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius,mPaint);
        mPaint.setColor(bombColor);
        canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius -distance,mPaint);
        mPaint.setColor(bombLineColor);
        canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius -distance*2,mPaint);
        mPaint.setColor(lightColor);
        canvas.drawCircle(bombCenterX,circleY, currentBlastCircleRadius -distance*3,mPaint);
        //掏空
        if (blastCircleRadiusPercent >0.65) {
            mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
            canvas.drawCircle(bombCenterX, circleY, currentBlastCircleRadius - maxBlastCircleRadius * 0.65f, mPaint);
            mPaint.setXfermode(null);
        }
        canvas.restoreToCount(save);
    }

    private void drawHeadLine(Canvas canvas) {
        canvas.save();
        mCamera.save();
        mCamera.rotate(bombTBRotate,0,-bombLRRotate);
        mMatrix.reset();
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-bombCenterX,-bombCenterY);
        mMatrix.postTranslate(bombCenterX,bombCenterY);
        canvas.concat(mMatrix);
        mPaint.setColor(bombLineColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPathMeasure.setPath(mHeadLinePath,false);
        mPath.reset();
        mPathMeasure.getSegment(0,mPathMeasure.getLength()*headLinePercent,mPath,true);
        canvas.drawPath(mPath,mPaint);
        //火光
        mPathMeasure.setPath(mPath,false);
        float length=mPathMeasure.getLength();
        mPathMeasure.getPosTan(length,mPathPosition,null);
        mPaint.setColor(Color.parseColor("#fbb42d"));
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(mPathPosition[0],mPathPosition[1],Math.max(bombLineWidth/1.3f*headLineLightRate,bombLineWidth/2*1.2f),mPaint);
        mPaint.setColor(Color.parseColor("#f34671"));
        mPath.reset();
        mPath.addCircle(mPathPosition[0],mPathPosition[1],bombLineWidth/2.5f*headLineLightRate, Path.Direction.CCW);
        mPaint.setPathEffect(mHeadEffect);
        canvas.drawPath(mPath,mPaint);
        mPaint.setPathEffect(null);
        mPaint.setColor(Color.WHITE);
        canvas.drawCircle(mPathPosition[0],mPathPosition[1], bombLineWidth /6.5f * headLineLightRate,mPaint);
        canvas.restore();
    }

    private void drawHead(Canvas canvas) {
        canvas.save();
        mCamera.save();
        mCamera.rotate(bombTBRotate,0,-bombLRRotate);
        mMatrix.reset();
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-bombCenterX,-(bombCenterY));
        mMatrix.postTranslate(bombCenterX,(bombCenterY));
        canvas.concat(mMatrix);

        mPaint.setStrokeWidth(bombLineWidth*0.8f);
        //内部
        mPaint.setColor(bombColor);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawPath(mHeadPath,mPaint);
        //边框
        mPaint.setColor(bombLineColor);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(mHeadPath,mPaint);
        mPaint.setStrokeWidth(bombLineWidth);
        canvas.restore();
    }

    private void drawBody(Canvas canvas) {
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(bombColor);
        canvas.drawCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2,mPaint);
        //左上角光点
        mPaint.setPathEffect(highLightPathEffect);
        mPaint.setColor(lightColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPath.reset();
        mPath.addCircle(bombCenterX,bombCenterY, highLightRadius, Path.Direction.CCW);
        canvas.drawPath(mPath,mPaint);
        //左上角的光边
        mPaint.setPathEffect(null);
        mRectF.set(bombCenterX-bodyRadius+bombLineWidth/2,bombCenterY-bodyRadius+bombLineWidth/2
                ,bombCenterX+bodyRadius-bombLineWidth/2,getMeasuredHeight()-bombLineWidth-bombLineWidth/2);
        canvas.drawArc(mRectF,160,100,false,mPaint);
        //拼接光边
        mPath.reset();
        mPath.addCircle(bombCenterX,bombCenterY,bodyRadius-bombLineWidth/2, Path.Direction.CCW);
        canvas.save();
        canvas.clipPath(mPath);//裁剪圆内

        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(lightColor);
        canvas.drawPath(mBodyLightPath,mPaint);
        canvas.restore();
    }


    private Point getPointInCircle(int circleX,int circleY,float radius,float angle){
        Point mPoint=new Point();
        mPoint.set((int)(circleX + radius * Math.cos(Math.toRadians(angle))),
                (int)(circleY+radius*Math.sin(Math.toRadians(angle))));
        return mPoint;
    }

    private void drawBodyBorder(Canvas canvas) {
        canvas.save();
        canvas.rotate(bombLRRotate,bombCenterX,bombCenterY);
        mPaint.setPathEffect(bodyDashPathEffect);
        mPaint.setColor(bombLineColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPath.reset();
        mPath.addCircle(bombCenterX,bombCenterY,bodyRadius, Path.Direction.CW);
        canvas.drawPath(mPath,mPaint);
        canvas.restore();
    }

    private void drawGround(Canvas canvas) {
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(bombLineColor);
        mPaint.setPathEffect(groundDashPathEffect);
        mPath.reset();
        mPath.moveTo(bombLineWidth/2,getMeasuredHeight()-bombLineWidth/2);
        mPath.lineTo(getMeasuredWidth()-bombLineWidth/2,getMeasuredHeight()-bombLineWidth/2);
        canvas.drawPath(mPath,mPaint);
    }

    private AnimatorSet set=new AnimatorSet();
    public void startAnim(){
        stopAnim();
        ValueAnimator faceTBAnim=getFaceTopBottomAnim();
        ValueAnimator faceLRAnim=getFaceLeftRightAnim();
        AnimatorSet faceChangeAnim=getFaceChangeAnim();
        set.play(getBlastAnim()).after(faceChangeAnim);
        set.play(faceChangeAnim).after(faceTBAnim);
        set.play(faceTBAnim).after(faceLRAnim);
        set.play(faceLRAnim).with(getHeadLineAnim());
        set.start();
    }

    public void stopAnim(){
        set.cancel();
        initData();
        invalidate();
    }

    private void initData() {
        faceTBOffset=0;
        bombTBRotate=0;
        bombLRRotate=15;
        faceLROffset=-faceMaxLROffset;
        currentBlastCircleRadius =0;
        blastCircleRadiusPercent=0;
        eyeRadius=eyeMaxRadius;
        headLinePercent=1;
        mouthWidthOffset=0;
        mouthHeightOffset =0;
        mouthOffsetPercent=0;
        mouthFSWidthOffset=0;
        mouthFSHeightOffset=0;
        headLineLightRate=0;
    }

    private int getFaceChangeAnimTime(){
        return 450;
    }

    private AnimatorSet getFaceChangeAnim(){
        AnimatorSet animatorSet=new AnimatorSet();
        //眼睛
        ValueAnimator valueAnimator= ValueAnimator.ofFloat(1,0,1.4f)
                .setDuration(getFaceChangeAnimTime());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                eyeRadius=eyeMaxRadius*(float) animation.getAnimatedValue();
                if (eyeRadius<eyeMinRadius){
                    eyeRadius=eyeMinRadius;
                }
            }
        });

        ValueAnimator mouthAnimator=ValueAnimator.ofFloat(0,1,0,1)
                .setDuration(getFaceChangeAnimTime());
        mouthAnimator.setInterpolator(new DecelerateInterpolator());
        mouthAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value= (float) animation.getAnimatedValue();
                if (animation.getAnimatedFraction()>0.75){//第一阶段还是第二阶段
                    mouthWidthOffset=mouthMaxWidthOffset*value;
                    mouthHeightOffset = mouthMaxHeightOffset *value;
                    mouthOffsetPercent=animation.getAnimatedFraction();
                }else{
                    mouthFSWidthOffset=mouthFSMaxWidthOffset*value;
                    mouthFSHeightOffset=mouthFSMaxHeightOffset*value;
                }
                invalidate();
            }
        });
        animatorSet.play(valueAnimator).with(mouthAnimator);
        return animatorSet;
    }

    private int getFaceTopBottomAnimTime(){
        return 300;
    }
    private int getFaceTopBottomAnimDelayTime(){
        return 200;
    }

    private ValueAnimator getFaceTopBottomAnim(){
        ValueAnimator objectAnimator= ValueAnimator.ofFloat(0,1)
                .setDuration(getFaceTopBottomAnimTime());
        objectAnimator.setStartDelay(getFaceTopBottomAnimDelayTime());
        objectAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value= (float) animation.getAnimatedValue();
                faceTBOffset= -faceMaxTBOffset*value;
                bombTBRotate= bombMaxTBRotate*value;
                invalidate();
            }
        });
        return objectAnimator;
    }

    private int getFaceLeftRightAnimTime(){
        return 1400;
    }
    private ValueAnimator getFaceLeftRightAnim(){
        ValueAnimator valueAnimator= ValueAnimator.ofFloat(-1,0,1,0)
                .setDuration(getFaceLeftRightAnimTime());
        valueAnimator.setInterpolator(new DecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value= (float) animation.getAnimatedValue();
                faceLROffset = faceMaxLROffset *value;
                bombLRRotate = -bombMaxLRRotate *value;
                if (Math.abs(value)<0.3&&animation.getAnimatedFraction()<0.6){
                    eyeRadius=Math.max(eyeMaxRadius*Math.abs(value),eyeMinRadius);
                }else{
                    eyeRadius=eyeMaxRadius;
                }
                invalidate();
            }
        });
        return valueAnimator;
    }

    private int getHeadLineAnimTime(){
        return getFaceLeftRightAnimTime()+getFaceTopBottomAnimTime()+getFaceTopBottomAnimDelayTime()+getFaceChangeAnimTime()+500;
    }
    private AnimatorSet getHeadLineAnim(){
        AnimatorSet animatorSet=new AnimatorSet();
        ValueAnimator valueAnimator= ValueAnimator.ofFloat(1f,0f)
                .setDuration(getHeadLineAnimTime());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                headLinePercent= (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        ValueAnimator valueAnimatorLight=ValueAnimator.ofFloat(0f,1.3f,0f)
                .setDuration(getHeadLineAnimTime()/5);
        valueAnimatorLight.setRepeatCount(5);
        valueAnimatorLight.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                headLineLightRate= (float) animation.getAnimatedValue();
            }
        });
        animatorSet.play(valueAnimator).with(valueAnimatorLight);
        return animatorSet;
    }

    private ValueAnimator getBlastAnim(){
        ValueAnimator valueAnimator= ValueAnimator.ofFloat(0,maxBlastCircleRadius)
                .setDuration(500);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if (animation.getAnimatedFraction()>0.7f){
                    initData();
                }
                currentBlastCircleRadius = (float) animation.getAnimatedValue();
                blastCircleRadiusPercent=animation.getAnimatedFraction();
                invalidate();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                initData();
                invalidate();
            }
        });
        return valueAnimator;
    }

    private float getRadianLength(float angle,float radius){
        return (float) (angle*Math.PI*radius/180f);
    }
}
布局中使用:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.a08_bomb.MainActivity">

    <com.example.a08_bomb.BombView
        android:id="@+id/bomb_view"
        android:layout_centerInParent="true"
        android:layout_width="300dp"
        android:layout_height="300dp" />

</RelativeLayout>

代码:
package com.example.a08_bomb;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final BombView bombView = findViewById(R.id.bomb_view);
        bombView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                bombView.startAnim();
            }
        });
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值