一種載入動畫的實現,一種載入動畫實現
記得看過上面的一個動畫設計,就試著實現了一下,首先是可以看到這個動畫由兩部分組成,一個圓圈的順時針轉動,另一個是圓點的直線運動,圓點之間有時間差,兩種運動疊加就形成了這種滾動的效果。
圖一、圖二、圖三
上面圖一顯示了只有圓圈旋轉的狀態,圖二是只有圓點直線運動的狀態,圖三是圖二中各個圓點添加時間差後的效果。
實現繪製點
這裡一共有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