Android水波纹效果

Android水波纹效果

最近学习了 Paint 和 Canvas 的相关知识,自定义 View 实现了一个水波纹效果
在这里插入图片描述

注释在代码里面已经补全了。直接看代码即可

package com.wuba.demo;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;

/**
 * Author silence.
 * Time:2019-08-14.
 * Desc:水波纹效果
 * 1.先绘制六个小圆
 * 2.绘制旋转动画
 * 3.绘制收缩动画
 * 4.绘制水波纹动画
 */
public class WaterRippleView extends View {

    private static final Long DURATION = 1500L;

    //背景颜色
    private int mBackGroundColor = Color.WHITE;

    //小圆半径
    private float mCircleRadius = 18;
    //小圆颜色
    private int[] mCircleColors = new int[]{
            Color.RED, Color.BLUE, Color.GREEN,
            Color.YELLOW, Color.BLACK, Color.GRAY
    };
    //小圆画笔
    private Paint mCirclePaint;

    //小圆组成大圆的半径
    private float mRotateRadius = 90;
    //大圆的坐标
    private float mCenterX, mCenterY;

    private RippleState mState;

    private ValueAnimator mAnimator;

    //当前大圆旋转角度
    private float mCurrentRotateAngle = 0;
    //当前大圆半径
    private float mCurrentRotateRadius = mRotateRadius;

    //扩散圆的画笔
    private Paint mHolePaint;
    //扩散圆的半径
    private float mCurrentHoleRadius = 0f;
    //斜对角线长度的一般,扩散圆最大半径
    private float mDistance;


    private static final int IDLE = 0;//初始化状态
    private static final int RUNNING = 1;//动画执行状态

    private int mAnimStatus = IDLE;


    public WaterRippleView(Context context) {
        this(context, null);
    }

    public WaterRippleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaterRippleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mState = new RotateState();

        mHolePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mHolePaint.setStyle(Paint.Style.STROKE);
        mHolePaint.setColor(mBackGroundColor);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w / 2f;
        mCenterY = h / 2f;
        mDistance = (float) (Math.hypot(w, h) / 2);
    }

    private void reset(){
        mCurrentRotateAngle = 0;
        mCurrentRotateRadius = mRotateRadius;
        mCurrentHoleRadius = 0f;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mState.onDraw(canvas);
    }

    private abstract class RippleState {
        abstract void onDraw(Canvas canvas);
    }

    private void drawBackground(Canvas canvas) {
        if (mCurrentHoleRadius > 0) {//绘制水波纹,水波纹效果通过空心圆实现
            //绘制空心圆
            float strokeWidth = mDistance - mCurrentHoleRadius;
            float radius = strokeWidth / 2 + mCurrentHoleRadius;
            mHolePaint.setStrokeWidth(strokeWidth);
            canvas.drawCircle(mCenterX, mCenterY, radius, mHolePaint);
        } else {//绘制其他动画的背景
            canvas.drawColor(mBackGroundColor);
        }
    }

    private void drawCircles(Canvas canvas) {
        float rotateAngle = (float) ((Math.PI * 2) / mCircleColors.length);
        for (int i = 0; i < mCircleColors.length; i++) {
            float angle = i * rotateAngle + mCurrentRotateAngle;
            float cx = (float) (Math.cos(angle) * mCurrentRotateRadius + mCenterX);
            float cy = (float) (Math.sin(angle) * mCurrentRotateRadius + mCenterY);
            mCirclePaint.setColor(mCircleColors[i]);
            canvas.drawCircle(cx, cy, mCircleRadius, mCirclePaint);
        }
    }

    /**
     * 六个小圆旋转动画
     */
    private class RotateState extends RippleState {

        public RotateState() {
            reset();
            mAnimator = ValueAnimator.ofFloat(0, (float) (Math.PI * 2));
            mAnimator.setRepeatCount(2);
            mAnimator.setDuration(DURATION);
            mAnimator.setInterpolator(new LinearInterpolator());
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotateAngle = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    mAnimStatus = RUNNING;
                }

                @Override
                public void onAnimationEnd(Animator animation) {
                    mState = new MergeState();
                }
            });
            mAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            drawBackground(canvas);
            drawCircles(canvas);
        }
    }

    /**
     * 缩放动画
     */
    private class MergeState extends RippleState {

        private MergeState() {
            mAnimator = ValueAnimator.ofFloat(mCircleRadius, mRotateRadius);
            mAnimator.setDuration(DURATION);
            mAnimator.setInterpolator(new OvershootInterpolator(10f));
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentRotateRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mState = new ExpandState();
                }
            });
            mAnimator.reverse();
        }

        @Override
        void onDraw(Canvas canvas) {
            drawBackground(canvas);
            drawCircles(canvas);
        }
    }

    /**
     * 绘制水波纹扩散动画
     */
    private class ExpandState extends RippleState {

        public ExpandState() {
            mAnimator = ValueAnimator.ofFloat(mCircleRadius, mDistance);
            mAnimator.setDuration(DURATION);
            mAnimator.setInterpolator(new LinearInterpolator());
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mCurrentHoleRadius = (float) animation.getAnimatedValue();
                    invalidate();
                }
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    mAnimStatus = IDLE;
                }
            });
            mAnimator.start();
        }

        @Override
        void onDraw(Canvas canvas) {
            drawBackground(canvas);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (mAnimStatus == IDLE) {
                mState = new RotateState();
            }
        }
        return super.onTouchEvent(event);
    }


}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值