大家一定看过支付宝支付成功时显示的那个打勾的动画,这次就带来这样一个控件,把动画封装成一个控件,再二次封装在对话
框里,调用时只需要写一句话,很方便。先看一下效果吧:
首先还是惯例的简单说一下原理吧。其实很简单,本质就是画一个图案,勾的图案就是画个圆弧,再画一段折线,其它图案同
理。然后所谓动画就是把这个图案绘制的过程一帧一帧迭代,这里直接用了系统提供的属性动画类ValueAnimator来实现迭代过
程。关于属性动画这里就不多说了,不了解的童鞋可以自行度娘。
废话了一堆,开始正题。这次的文件数量有点多,我们一个一个来。
我把loading、打勾、打叉、感叹号四个动画每一个单独封装成一个View的子类,分别叫LoadingView、SucceedView、
FailedView、WarningView。上本体:
LoadingView.java:
public class LoadingView extends View {
private Context context;
// 动画播放周期
private int duration = 1000;
// 动画控制器
private Interpolator interpolator = new LinearInterpolator();
// 是否正在播放loading动画
private boolean isLoading;
public LoadingView(Context context) {
this(context, null);
}
public LoadingView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public LoadingView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
this.context = context;
setBackgroundDrawable(context.getResources().getDrawable(R.drawable.circle_loading));
}
/**
* 开始播放动画
*/
public void start() {
if (isLoading) {
return;
}
isLoading = true;
RotateAnimation animation = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(duration);
animation.setInterpolator(interpolator);
animation.setRepeatCount(-1);
startAnimation(animation);
}
/**
* 停止播放动画
*/
public void stop() {
clearAnimation();
isLoading = false;
}
/**
* 设置动画播放周期
* @param duration 播放周期,单位毫秒
*/
public void setDuration(int duration) {
this.duration = duration;
}
/**
* 设置动画控制器
* @param interpolator
*/
public void setInterpolator(Interpolator interpolator) {
this.interpolator = interpolator;
}
/**
* 获取是否正在播放loading动画
* @return
*/
public boolean isLoading() {
return isLoading;
}
}
SucceedView.java:
public class SucceedView extends View {
private Context context;
private int width;
private int height;
private int radius;
private float startX;
private float startY;
private float middleX;
private float middleY;
private float endX;
private float endY;
// 图案线宽
private int lineWidth;
// 图案线颜色
private int lineColor = Color.parseColor("#ADE584");
// 动画播放时间
private int duration = 1500;
// 动画控制器
private Interpolator interpolator = new AccelerateDecelerateInterpolator();
private Paint circlePaint;
private Paint linePaint;
private float progress;
private boolean isDraw;
// 动画播放回调
private OnShowAnimationListener listener;
public SucceedView(Context context) {
this(context, null);
}
public SucceedView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public SucceedView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
private void init() {
if (lineWidth == 0) lineWidth = dp2px(3);
if (circlePaint == null) circlePaint = new Paint();
circlePaint.setStrokeWidth(lineWidth);
circlePaint.setColor(lineColor);
circlePaint.setStyle(Paint.Style.STROKE);
circlePaint.setAntiAlias(true);
circlePaint.setStrokeCap(Paint.Cap.ROUND);
if (linePaint == null) linePaint = new Paint();
linePaint.setStrokeWidth(1.5f * lineWidth);
linePaint.setColor(lineColor);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setAntiAlias(true);
linePaint.setStrokeCap(Paint.Cap.ROUND);
startX = lineWidth / 2 + radius * 2 / 5;
startY = lineWidth / 2 + radius;
middleX = lineWidth / 2 + radius - 2 * lineWidth;
middleY = lineWidth / 2 + radius * 7 / 5;
endX = lineWidth / 2 + radius + radius * (float) Math.cos(2 * Math.PI * 37.5 / 360);
endY = lineWidth + radius - radius * (float) Math.sin(2 * Math.PI * 37.5 / 360);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
width = getMeasuredWidth();
height = width;
radius = (width / 2 - lineWidth / 2);
getLayoutParams().height = height;
init();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
doDraw(canvas);
}
/**
* 绘制图案
*
* @param canvas
*/
private void doDraw(Canvas canvas) {
if (progress > 0) {
// 画外面的圈
if (progress <= 0.5) {
canvas.drawArc(new RectF(lineWidth / 2, lineWidth / 2, width - lineWidth / 2, height - lineWidth / 2), -60, -315 * (progress / (float) 0.6), false, circlePaint);
// 画勾的左半部分
} else if (progress <= 0.7) {
canvas.drawArc(new RectF(lineWidth / 2, lineWidth / 2, width - lineWidth / 2, height - lineWidth / 2), -60, -315, false, circlePaint);
canvas.drawLine(startX, startY, startX + (middleX - startX) * (progress - 0.5f) / 0.2f, startY + (middleY - startY) * (progress - 0.5f) / 0.2f, linePaint);
// 画勾的右半部分
} else {
canvas.drawArc(new RectF(lineWidth / 2, lineWidth / 2, width - lineWidth / 2, height - lineWidth / 2), -60, -315, false, circlePaint);
canvas.drawLine(startX, startY, middleX, middleY, linePaint);
canvas.drawLine(middleX, middleY, middleX + (endX - middleX) * (progress - 0.7f) / 0.3f, middleY + (endY - middleY) * (progress - 0.7f) / 0.3f, linePaint);
}
}
}
/**
* 开始播放动画
*/
public void start() {
if (isDraw) {
return;
}
isDraw = true;
ValueAnimator animator = new ValueAnimator().ofFloat(0, 1, 1);
animator.setDuration(duration);
animator.setInterpolator(interpolator);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
if (isDraw) {
progress = (float) animation.getAnimatedValue();
invalidate();
}
}
});
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
if (listener != null) listener.onStart();
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
isDraw = false;
if (listener != null) listener.onCancel();
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
isDraw = false;
if (listener != null) listener.onFinish();
}
});
animator.start();
}
/**
* 停止播放动画方法
*/
public void stop() {
isDraw &