天天看點

一種加載動畫的實作

一種加載動畫的實作

記得看過上面的一個動畫設計,就試着實作了一下,首先是可以看到這個動畫由兩部分組成,一個圓圈的順時針轉動,另一個是圓點的直線運動,圓點之間有時間差,兩種運動疊加就形成了這種滾動的效果。

一種加載動畫的實作
一種加載動畫的實作
一種加載動畫的實作

圖一、圖二、圖三

上面圖一顯示了隻有圓圈旋轉的狀态,圖二是隻有圓點直線運動的狀态,圖三是圖二中各個圓點添加時間差後的效果。

實作

繪制點

這裡一共有15個圓點,相位偏差是360/15=24˚

for (int i = ; i < POINT_NUM; ++i) {
    float x = mRadius * -(float) Math.sin(DEGREE *  * i);
    float y = mRadius * -(float) Math.cos(DEGREE *  * i);

    ArcPoint point = new ArcPoint(x, y, COLORS[i % ]);
    mArcPoint[i] = point;
}

private final double DEGREE = Math.PI / ;
private static final int POINT_NUM = ;
           

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( * factor);
        float x, y;
        for (int i = ; 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 - f / POINT_NUM * index) * ;
    if (itemFactor < f) {
        itemFactor = f;
    } else if (itemFactor > f) {
        itemFactor = f;
    }
    return mInterpolator.getInterpolation(itemFactor);
}
           

這裡設計每個點直線運動的時間是周期的

1/3

,那剩餘的

2/3=0.66

就是從第一個點開始到最後一個點開始運動的時間,通過

factor - f / POINT_NUM * index
           

就可以得到每個圓點的起始時間,再

*3

将其換算到直線運動的時間上。

将上面的運動組合起來就得到了完整的

onDraw

方法

@Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        canvas.translate(mCenter.x, mCenter.y);

        float factor = getFactor();
        canvas.rotate( * factor);
        float x, y;
        for (int i = ; i < POINT_NUM; ++i) {
            mPaint.setColor(mArcPoint[i].color);
            float itemFactor = getItemFactor(i, factor);
            x = mArcPoint[i].x -  * mArcPoint[i].x * itemFactor;
            y = mArcPoint[i].y -  * mArcPoint[i].y * itemFactor;
            canvas.drawCircle(x, y, mPointRadius, mPaint);
        }

        canvas.restore();
        if (mStartAnim) {
            postInvalidate();
        }
    }
           

Source code

源碼在這裡 https://github.com/Fichardu/CircleProgress