效果:
旋转加载动画效果
效果分析:
第一步旋转小球
1.1通过integer-array来定义显示的小球个数和颜色
1.2 Math.PI * 2 / 小球个数 得到小球所占角度的平均数,得到每个小球圆点的角度值
1.3.指定大外圆的半径,通过三角函数计算每个小球的圆点的坐标,绘制小球
1.4利用属性动画ofFloat 0到360度获取改变的角度,invalidate(),让小球旋转起来
/**
* 旋转动画绘制
*/
private ValueAnimator rotateAnimator;
class RotateStatus extends AnimatorStatus {
public RotateStatus() {
rotateAnimator = ObjectAnimator.ofFloat(0f, (float) (2 * Math.PI));
rotateAnimator.setDuration(ANIMATOR_DURATION);
rotateAnimator.setRepeatCount(-1);
rotateAnimator.setInterpolator(new LinearInterpolator());
rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mChangeAngle = (float) animation.getAnimatedValue();
invalidate();
}
});
rotateAnimator.start();
}
@Override
void onDraw(Canvas canvas) {
canvas.drawColor(getResources().getColor(android.R.color.white));
for (int i = 0; i < mColorList.length; i++) {
double angle = oneAngle * i + mChangeAngle;
int circleCenterX = (int) (mOutRadius * Math.cos(angle));
int circleCenterY = (int) (mOutRadius * Math.sin(angle));
mPaint.setColor(mColorList[i]);
canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
}
}
@Override
void cancel() {
rotateAnimator.cancel();
}
}
第二步拿到数据聚合向中间靠拢动画
2.1 大外圆半径就是每个小球需要变化的距离,即通过属性动画来改变大外圆的半径
2.2 通过三角函数计算小球改变的圆点坐标
2.3 AnticipateInterpolator插值器来实现开始前向外扩散一下的效果
/**
* 聚合动画绘制
*/
private ValueAnimator drawCloseAnimator;
class DrawCloseStatus extends AnimatorStatus {
public DrawCloseStatus() {
drawCloseAnimator = ObjectAnimator.ofFloat(mOutRadius, 0f);
drawCloseAnimator.setDuration(ANIMATOR_DURATION / 5);
drawCloseAnimator.setInterpolator(new AnticipateInterpolator(5f));
drawCloseAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCircleDistance = (float) animation.getAnimatedValue();
invalidate();
}
});
drawCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mAnimatorStatus = new SpreadStatus();
}
});
drawCloseAnimator.start();
}
@Override
void onDraw(Canvas canvas) {
canvas.drawColor(getResources().getColor(android.R.color.white));
for (int i = 0; i < mColorList.length; i++) {
double angle = oneAngle * i + mChangeAngle;
int circleCenterX = (int) (mCircleDistance * Math.cos(angle));
int circleCenterY = (int) (mCircleDistance * Math.sin(angle));
mPaint.setColor(mColorList[i]);
canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
}
}
@Override
void cancel() {
drawCloseAnimator.cancel();
}
}
第三步向外扩散动画
3.1 向外扩散的圆的半径为控件对角线的一半,即通过三角函数斜边等于对边的平方加邻边的平方开根号
3.2 画笔Panit strokeWidth 的大小变化为控件对角线的一半 到 0
3.2 向外扩散圆的半径大小变化为0到控件对角线的一半 + Panit strokeWidth 的1/2;
/**
* 扩散动画
*/
private ValueAnimator spreadAnimator;
class SpreadStatus extends AnimatorStatus {
private float spreadDistance;
private float changeRadius;
public SpreadStatus() {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(getResources().getColor(android.R.color.white));
spreadDistance = (float) Math.sqrt(mCenterX * mCenterX + mCenterY * mCenterY);
spreadAnimator = ObjectAnimator.ofFloat(0, spreadDistance);
spreadAnimator.setDuration(ANIMATOR_DURATION / 5);
spreadAnimator.setInterpolator(new LinearInterpolator());
spreadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
changeRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
spreadAnimator.start();
}
@Override
void onDraw(Canvas canvas) {
float strokeWidth = spreadDistance - changeRadius;
mPaint.setStrokeWidth(strokeWidth);
canvas.drawCircle(mCenterX, mCenterY, changeRadius + strokeWidth / 2, mPaint);
}
@Override
void cancel() {
spreadAnimator.cancel();
}
}
实现思路都在上面了,下方附上完整代码
<integer-array name="loading_circle_color_list">
<item>@color/color_cd6155</item>
<item>@color/color_48c9b0</item>
<item>@color/color_af7ac5</item>
<item>@color/color_f4d03f</item>
<item>@color/color_9c640c</item>
<item>@color/color_5dade2</item>
</integer-array>
public class LoadingView extends View {
private int mColorList[];
private int mCenterX, mCenterY;
private Paint mPaint;
private double oneAngle;
private int mOutRadius;
private int mCircleRadius;
private float mChangeAngle;
private long ANIMATOR_DURATION = 3500;
private AnimatorStatus mAnimatorStatus;
private float mCircleDistance;
public LoadingView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mColorList = getResources().getIntArray(R.array.loading_circle_color_list);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setDither(true);
oneAngle = Math.PI * 2 / mColorList.length;
}
@Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
mCenterX = width / 2;
mCenterY = height / 2;
mOutRadius = width / 4;
mCircleRadius = mOutRadius / 8;
}
@Override
protected void onDraw(Canvas canvas) {
if (mAnimatorStatus == null) {
mAnimatorStatus = new RotateStatus();
}
mAnimatorStatus.onDraw(canvas);
}
public void dataDisplay() {
if (mAnimatorStatus instanceof RotateStatus) {
mAnimatorStatus.cancel();
mAnimatorStatus = new DrawCloseStatus();
}
}
/**
* 旋转动画绘制
*/
private ValueAnimator rotateAnimator;
class RotateStatus extends AnimatorStatus {
public RotateStatus() {
rotateAnimator = ObjectAnimator.ofFloat(0f, (float) (2 * Math.PI));
rotateAnimator.setDuration(ANIMATOR_DURATION);
rotateAnimator.setRepeatCount(-1);
rotateAnimator.setInterpolator(new LinearInterpolator());
rotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mChangeAngle = (float) animation.getAnimatedValue();
invalidate();
}
});
rotateAnimator.start();
}
@Override
void onDraw(Canvas canvas) {
canvas.drawColor(getResources().getColor(android.R.color.white));
for (int i = 0; i < mColorList.length; i++) {
double angle = oneAngle * i + mChangeAngle;
int circleCenterX = (int) (mOutRadius * Math.cos(angle));
int circleCenterY = (int) (mOutRadius * Math.sin(angle));
mPaint.setColor(mColorList[i]);
canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
}
}
@Override
void cancel() {
rotateAnimator.cancel();
}
}
/**
* 聚合动画绘制
*/
private ValueAnimator drawCloseAnimator;
class DrawCloseStatus extends AnimatorStatus {
public DrawCloseStatus() {
drawCloseAnimator = ObjectAnimator.ofFloat(mOutRadius, 0f);
drawCloseAnimator.setDuration(ANIMATOR_DURATION / 5);
drawCloseAnimator.setInterpolator(new AnticipateInterpolator(5f));
drawCloseAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCircleDistance = (float) animation.getAnimatedValue();
invalidate();
}
});
drawCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mAnimatorStatus = new SpreadStatus();
}
});
drawCloseAnimator.start();
}
@Override
void onDraw(Canvas canvas) {
canvas.drawColor(getResources().getColor(android.R.color.white));
for (int i = 0; i < mColorList.length; i++) {
double angle = oneAngle * i + mChangeAngle;
int circleCenterX = (int) (mCircleDistance * Math.cos(angle));
int circleCenterY = (int) (mCircleDistance * Math.sin(angle));
mPaint.setColor(mColorList[i]);
canvas.drawCircle(mCenterX + circleCenterX, mCenterY + circleCenterY, mCircleRadius, mPaint);
}
}
@Override
void cancel() {
drawCloseAnimator.cancel();
}
}
/**
* 扩散动画
*/
private ValueAnimator spreadAnimator;
class SpreadStatus extends AnimatorStatus {
private float spreadDistance;
private float changeRadius;
public SpreadStatus() {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(getResources().getColor(android.R.color.white));
spreadDistance = (float) Math.sqrt(mCenterX * mCenterX + mCenterY * mCenterY);
spreadAnimator = ObjectAnimator.ofFloat(0, spreadDistance);
spreadAnimator.setDuration(ANIMATOR_DURATION / 5);
spreadAnimator.setInterpolator(new LinearInterpolator());
spreadAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
changeRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
spreadAnimator.start();
}
@Override
void onDraw(Canvas canvas) {
float strokeWidth = spreadDistance - changeRadius;
mPaint.setStrokeWidth(strokeWidth);
canvas.drawCircle(mCenterX, mCenterY, changeRadius + strokeWidth / 2, mPaint);
}
@Override
void cancel() {
spreadAnimator.cancel();
}
}
abstract class AnimatorStatus {
abstract void onDraw(Canvas canvas);
void cancel() {
}
}
}
网友评论