package com.example.loadingviewdemo;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;
public class RotateLoading extends View {
private int color;
private int width;
private int shadowPosition;
private static final int DEFAULT_WIDTH = 6;// 默认宽度为6
private static final int DEFAULT_SHADOW_POSITION = 2;
private Paint mPaint;// 画笔
private float arc;
private RectF loadingRectF;
private RectF shadowRectF;
private boolean isStart = false;
private int topDegree = 10;// 上面的角度
private int bottomDegree = 190;// 下面的角度
private boolean changeBigger = true;
public RotateLoading(Context context) {
super(context);
initView(context, null);
}
public RotateLoading(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public RotateLoading(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
color = Color.WHITE;
width = dpToPx(context, DEFAULT_WIDTH);
shadowPosition = dpToPx(context, DEFAULT_SHADOW_POSITION);
if (null != attrs) {
TypedArray attr = context.obtainStyledAttributes(attrs,
R.styleable.RotateLoading);
color = attr.getColor(R.styleable.RotateLoading_loading_color,
Color.WHITE);
width = attr.getDimensionPixelSize(
R.styleable.RotateLoading_loading_width,
dpToPx(context, DEFAULT_WIDTH));
shadowPosition = attr.getInt(
R.styleable.RotateLoading_shadow_position,
DEFAULT_SHADOW_POSITION);
attr.recycle();
}
mPaint = new Paint();
mPaint.setColor(color);// 设置颜色
mPaint.setAntiAlias(true);// 设置抗锯齿
mPaint.setStyle(Paint.Style.STROKE);// 样式是STROKE空心
mPaint.setStrokeWidth(width);
mPaint.setStrokeCap(Paint.Cap.ROUND);
}
/** 数据可以在onMeasure方法中初始化 */
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
arc = 10;
loadingRectF = new RectF(2 * width, 2 * width, w - 2 * width, h - 2
* width);
shadowRectF = new RectF(2 * width + shadowPosition, 2 * width
+ shadowPosition, w - 2 * width + shadowPosition, h - 2 * width
+ shadowPosition);
Log.e("onSizeChanged", "----" + w + "----" + h + "----" + oldw + "----"
+ oldh);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.e("onDraw", "----");
if (!isStart) {
return; // 启动动画的时候,为true
}
// 绘制阴影
mPaint.setColor(Color.parseColor("#1a000000"));
canvas.drawArc(shadowRectF, topDegree, arc, false, mPaint);// 绘制矩形区域,开始角度,连续角度,不用中心点,画笔描边的
canvas.drawArc(shadowRectF, bottomDegree, arc, false, mPaint);// 绘制另一半的弧
// 绘制旋转的两个半弧
mPaint.setColor(color);
canvas.drawArc(loadingRectF, topDegree, arc, false, mPaint);
canvas.drawArc(loadingRectF, bottomDegree, arc, false, mPaint);
// 每次绘制一次都要整体旋转10度
topDegree += 10;
bottomDegree += 10;
// 大于360度的时候就要重头开始
if (topDegree > 360) {
topDegree = topDegree - 360;
}
if (bottomDegree > 360) {
bottomDegree = bottomDegree - 360;
}
if (changeBigger) {
if (arc < 160) {
arc += 2.5;
invalidate();
}
} else {
if (arc > 10) {
arc -= 5;
invalidate();
}
}
if (arc == 160 || arc == 10) {
changeBigger = !changeBigger;
invalidate();
}
}
/** dp转化为px */
private int dpToPx(Context context, int dpValue) {
int px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpValue, context.getResources().getDisplayMetrics());
return px;
}
public void start() {
startAnimator();
isStart = true;
invalidate();
}
public void stop() {
stopAnimator();
invalidate();
}
@SuppressLint("NewApi")
private void startAnimator() {
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX",
0.0f, 1);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY",
0.0f, 1);
scaleXAnimator.setDuration(300);
scaleXAnimator.setInterpolator(new LinearInterpolator());
scaleYAnimator.setDuration(300);
scaleXAnimator.setInterpolator(new LinearInterpolator());
AnimatorSet animationSet = new AnimatorSet();
animationSet.playTogether(scaleXAnimator, scaleYAnimator);// 组合动画一起执行
animationSet.start();
}
@SuppressLint("NewApi")
private void stopAnimator() {
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX",
1, 0);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY",
1, 0);
scaleXAnimator.setDuration(300);
scaleXAnimator.setInterpolator(new LinearInterpolator());
scaleYAnimator.setDuration(300);
scaleYAnimator.setInterpolator(new LinearInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleXAnimator, scaleYAnimator);
animatorSet.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator arg0) {
// TODO Auto-generated method stub
isStart = false;
}
@Override
public void onAnimationCancel(Animator arg0) {
// TODO Auto-generated method stub
}
});
animatorSet.start();
}
public boolean isStart() {
return isStart;
}
}
invalidate方法会在将来某个时间段会使这个View失效,再次重新绘制,会再次调用onDraw方法,在主线程中绘制图形,这就达到了一直绘制的效果,但是也可以封装一个Runnable类,调用view的post方法,可以达到类似的效果