记得看过上面的一个动画设计,就试着实现了一下,首先是可以看到这个动画由两部分组成,一个圆圈的顺时针转动,另一个是圆点的直线运动,圆点之间有时间差,两种运动叠加就形成了这种滚动的效果。
图一、图二、图三
上面图一显示了只有圆圈旋转的状态,图二是只有圆点直线运动的状态,图三是图二中各个圆点添加时间差后的效果。
实现
绘制点
这里一共有15个圆点,相位偏差是360/15=24?
for (int i = 0; i < POINT_NUM; ++i) {
float x = mRadius * -(float) Math.sin(DEGREE * 24 * i);
float y = mRadius * -(float) Math.cos(DEGREE * 24 * i);
ArcPoint point = new ArcPoint(x, y, COLORS[i % 3]);
mArcPoint[i] = point;
}
private final double DEGREE = Math.PI / 180;
private static final int POINT_NUM = 15;
ArcPoint是点的定义,包括位置和颜色
static class ArcPoint {
float x;
float y;
int color;
ArcPoint(float x, float y, int color) {
this.x = x;
this.y = y;
this.color = color;
}
}
绘制圆圈的旋转
可以固定点不动,通过旋转canvas来实现
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.translate(mCenter.x, mCenter.y);
float factor = getFactor();
canvas.rotate(36 * factor);
float x, y;
for (int i = 0; i < POINT_NUM; ++i) {
mPaint.setColor(mArcPoint[i].color);
// float itemFactor = getItemFactor(i, factor);
x = mArcPoint[i].x;// - 2 * mArcPoint[i].x * itemFactor;
y = mArcPoint[i].y;// - 2 * mArcPoint[i].y * itemFactor;
canvas.drawCircle(x, y, mPointRadius, mPaint);
}
canvas.restore();
if (mStartAnim) {
postInvalidate();
}
}
这样就可以得到图一圆圈旋转的动画,这里固定了旋转角度36
,如果是360
就可以看到一个完整的旋转。
这里旋转角度为什么取36
?看完整效果,其实每个点在直线移动后,转动1.5
个相位偏差也就是24*1.5=36
,就可以和其实点的图形重合,而且因为圆点的颜色每三个重复一次,所以经过36度的旋转,新圆点位置和动画开始状态看上去就是一样的。
给圆点添加起始偏移时间
每个点运动的起始时间是不同的,如果一起运动就会得到图二的效果,我们看怎么从总的时间得到每个圆点的运动时间,也就是
float itemFactor = getItemFactor(i, factor);
private float getItemFactor(int index, float factor) {
float itemFactor = (factor - 0.66f / POINT_NUM * index) * 3;
if (itemFactor < 0f) {
itemFactor = 0f;
} else if (itemFactor > 1f) {
itemFactor = 1f;
}
return mInterpolator.getInterpolation(itemFactor);
}
这里设计每个点直线运动的时间是周期的1/3
,那剩余的2/3=0.66
就是从第一个点开始到最后一个点开始运动的时间,通过
factor - 0.66f / POINT_NUM * index
就可以得到每个圆点的起始时间,再*3
将其换算到直线运动的时间上。
将上面的运动组合起来就得到了完整的onDraw
方法
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.translate(mCenter.x, mCenter.y);
float factor = getFactor();
canvas.rotate(36 * factor);
float x, y;
for (int i = 0; i < POINT_NUM; ++i) {
mPaint.setColor(mArcPoint[i].color);
float itemFactor = getItemFactor(i, factor);
x = mArcPoint[i].x - 2 * mArcPoint[i].x * itemFactor;
y = mArcPoint[i].y - 2 * mArcPoint[i].y * itemFactor;
canvas.drawCircle(x, y, mPointRadius, mPaint);
}
canvas.restore();
if (mStartAnim) {
postInvalidate();
}
}
Source code
源码在这里 https://github.com/Fichardu/CircleProgress
时间: 2024-11-19 22:38:48