先看效果如下:

拆分需求: 外部有一个圆圈 内部一个圆切着内圆做圆周运动
首先绘制外圆圈,我是直接绘制一个圆弧
canvas.drawArc( left, top, right, bottom, 0,
360,false,outCircle);
绘制内部圆圈,因为内部圆是切着外圆运动的所以需要用到三角函数知识,当前的内圆旋转角度是已知的,圆的半径也是已知,计算当前点的x,y

float x = (float) (Math.sin(rotateAngle) * (circle - strokeWidth/2 - inCircularR-30) );
float y = (float) (Math.cos(rotateAngle)*(circle - strokeWidth/2- inCircularR-30));
//绘制内置圆圈
canvas.drawCircle(circle+x,circle+y,inCircularR,inCircular);
然后添加数值动画,使其动起来
valueAnimator = ValueAnimator.ofFloat(1);
valueAnimator.setDuration(100000);
valueAnimator.setRepeatCount(-1);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float progress = (float) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: "+progress);
rotateAngle = 360 * progress;
Log.d(TAG, "onAnimationUpdate: "+rotateAngle);
invalidate();
}
});
valueAnimator.start();
其实还有一种更简单的方法去实现,直接旋转画布,就不用去使用三角函数去动态计算了
完整代码如下:
public class RotateProgress extends View {
private static final String TAG = "RotateProgress";
//外圈
Paint outCircle;
//内圆
Paint inCircular;
float strokeWidth = UtilView.sp2px(18);
//旋转角度
float rotateAngle = 90;
//旋转内圆圈的半径
float inCircularR = UtilView.dip2px(18);
ValueAnimator valueAnimator = null;
public RotateProgress(Context context) {
this(context,null);
}
public RotateProgress(Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public RotateProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
outCircle = initPaint();
outCircle.setStyle(Paint.Style.STROKE);
outCircle.setStrokeWidth(strokeWidth);
inCircular = initPaint();
inCircular.setStyle(Paint.Style.FILL);
}
private Paint initPaint() {
Paint paint = new Paint();
paint.setAntiAlias(true);
return paint;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float circle = getWidth()/2;
//绘制外圈
float left = 0 + strokeWidth/2;
float top = 0+strokeWidth/2;
float right = getWidth() - strokeWidth/2;
float bottom = getHeight() - strokeWidth/2;
canvas.drawArc( left, top, right, bottom, 0,
360,false,outCircle);
float x = (float) (Math.sin(rotateAngle) * (circle - strokeWidth/2 - inCircularR-30) );
float y = (float) (Math.cos(rotateAngle)*(circle - strokeWidth/2- inCircularR-30));
//绘制内置圆圈
canvas.drawCircle(circle+x,circle+y,inCircularR,inCircular);
Log.d(TAG, "onDraw: x"+x+" y"+y);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(Math.min(width,height),Math.min(width,height));
}
public void startLoading(){
valueAnimator = ValueAnimator.ofFloat(1);
valueAnimator.setDuration(100000);
valueAnimator.setRepeatCount(-1);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float progress = (float) animation.getAnimatedValue();
Log.d(TAG, "onAnimationUpdate: "+progress);
rotateAngle = 360 * progress;
Log.d(TAG, "onAnimationUpdate: "+rotateAngle);
invalidate();
}
});
valueAnimator.start();
}
public void stopAnimator(){
if(valueAnimator != null){
valueAnimator.cancel();
valueAnimator = null;
}
}
}