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);
}
}