今天学习了一下自定义 View 实现启动页面动画到效果,上一下效果图
简单说一下过程
1、首先画白色背景和六个不同颜色到小球
白色背景直接 canvas.drawColor(backgroundColor);
小球这里说一下,六个小球围成一个圆,那么我们就先要计算出来两个小球之间的角度是多少
获取圆的周长除以小球个数
//先获取圆球之间的角度 圆周长 2PI
float rotateAngle = (float) ((Math.PI * 2) / circleColor.length);
然后 for 循环绘制小球
canvas.drawCircle(float cx, float cy, float radius, @NonNull Paint paint)
首先需要确定圆心坐标,半径是咱们规定好的
计算cx,cy需要一点点三角函数的知识
如图
贴上计算代码
//先获取圆球之间的角度 圆周长 2PI
float rotateAngle = (float) ((Math.PI * 2) / circleColor.length);
for (int i = 0; i < circleColor.length; i++) {
//x=r*cons(a)+cenX
//y=r*sin(a)+cenY
float angle = i * rotateAngle + mCurrentRotateAngle;
float cx = (float) (Math.cos(angle) * mCurrentRotateRadius + mCenterX);
float cy = (float) (Math.sin(angle) * mCurrentRotateRadius + mCenterY);
mPaint.setColor(circleColor[i]);
canvas.drawCircle(cx, cy, smallCircleRadius, mPaint);
}
然后我们在写一个 ValueAnimator 用来控制小球旋转的
valueAnimator = ValueAnimator.ofFloat(0, (float) (Math.PI * 2));//从0开始 圆的一周结束
valueAnimator.setRepeatCount(2);//次数
valueAnimator.setDuration(mRotateDuration);//时长
valueAnimator.setInterpolator(new LinearInterpolator());//匀速
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentRotateAngle = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashState = new MerginState();
}
});
valueAnimator.start();
这个时候就可以看到六个小球在屏幕中间 开始旋转了
2、旋转完后 小球开始扩散后中心聚合
valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, circleRadius);
valueAnimator.setDuration(mRotateDuration);
valueAnimator.setInterpolator(new OvershootInterpolator(10f));
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentRotateRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashState = new ExpandState();
}
});
valueAnimator.reverse();
3、最后就是我们的波纹效果了
valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, mDistance);
valueAnimator.setDuration(mRotateDuration);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentHoleRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
到此炫酷的启动动画就已经完成了,是不是很简单那,上一个完整的自己的 View 类
/**
* @author wavewave
* @CreateDate: 2019-07-16 22:46
* @Description:
* @Version: 1.0
*/
public class SplashView extends View {
//背景颜色
private int backgroundColor = Color.WHITE;
private int[] circleColor = new int[]{
Color.RED, Color.GREEN, Color.BLUE,
Color.GRAY, Color.DKGRAY, Color.BLACK};
private int smallCircleRadius = 10;
private int circleRadius = 99;
private float mCenterX, mCenterY;
private float mDistance;
private Paint mPaint;
private SplashState splashState;
private int mRotateDuration = 800;
private float mCurrentRotateRadius = circleRadius;
public SplashView(Context context) {
this(context, null);
}
public SplashView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public SplashView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCenterX = w * 1f / 2;
mCenterY = h * 1f / 2;
mDistance = (float) (Math.hypot(w, h) / 2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (splashState == null) {
splashState = new RotateState();
}
splashState.drawState(canvas);
}
//动画效果 6个不同颜色的球围城一个圆 ,开始旋转。然后扩散再聚合到中心,最后水波纹效果
/**
* 抽象类
* 表示绘制状态
*/
public abstract class SplashState {
abstract void drawState(Canvas canvas);
}
/**
* 绘制背景颜色
*
* @param canvas
*/
private void drawBackground(Canvas canvas) {
if (mCurrentHoleRadius > 0) {//第三种动画 绘制空心圆
float strokeWidth = mDistance - mCurrentHoleRadius;
float radius = strokeWidth / 2 + mCurrentHoleRadius;
mPaint.setStrokeWidth(radius);
canvas.drawCircle(mCenterX, mCenterY, radius, mPaint);
} else {
canvas.drawColor(backgroundColor);
}
}
/**
* 绘制小球
*
* @param canvas
*/
private void drawCircle(Canvas canvas) {
//先获取圆球之间的角度 圆周长 2PI
float rotateAngle = (float) ((Math.PI * 2) / circleColor.length);
for (int i = 0; i < circleColor.length; i++) {
//x=r*cons(a)+cenX
//y=r*sin(a)+cenY
float angle = i * rotateAngle + mCurrentRotateAngle;
float cx = (float) (Math.cos(angle) * mCurrentRotateRadius + mCenterX);
float cy = (float) (Math.sin(angle) * mCurrentRotateRadius + mCenterY);
mPaint.setColor(circleColor[i]);
canvas.drawCircle(cx, cy, smallCircleRadius, mPaint);
}
}
private float mCurrentRotateAngle;
private ValueAnimator valueAnimator;
//1 旋转
private class RotateState extends SplashState {
public RotateState() {
valueAnimator = ValueAnimator.ofFloat(0, (float) (Math.PI * 2));//从0开始 圆的一周结束
valueAnimator.setRepeatCount(2);//次数
valueAnimator.setDuration(mRotateDuration);//时长
valueAnimator.setInterpolator(new LinearInterpolator());//匀速
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentRotateAngle = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashState = new MerginState();
}
});
valueAnimator.start();
}
@Override
void drawState(Canvas canvas) {
//绘制白色背景
drawBackground(canvas);
//绘制圆
drawCircle(canvas);
}
}
//2 扩展聚合
private class MerginState extends SplashState {
public MerginState() {
valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, circleRadius);
valueAnimator.setDuration(mRotateDuration);
valueAnimator.setInterpolator(new OvershootInterpolator(10f));
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentRotateRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashState = new ExpandState();
}
});
valueAnimator.reverse();
}
@Override
void drawState(Canvas canvas) {
//绘制白色背景
drawBackground(canvas);
//绘制圆
drawCircle(canvas);
}
}
private float mCurrentHoleRadius;
//3 波纹效果
private class ExpandState extends SplashState {
public ExpandState() {
valueAnimator = ValueAnimator.ofFloat(smallCircleRadius, mDistance);
valueAnimator.setDuration(mRotateDuration);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentHoleRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}
@Override
void drawState(Canvas canvas) {
drawBackground(canvas);
}
}
}
如果有什么不对地方,请大家多多指正!欢迎评论