Gif(1)-載入檢視-交替圓效果

木漿果發表於2018-04-27

依然是個收藏已久的Gif,今天來實現一下。

記憶裡好像是有人已經實現過了。剛才去找了下,又沒找到。如果哪個朋友看到過過,給我發下,我來對比下,我想總會又收穫的。Gif如下圖。

alterCircle

效果圖如下:

device

原理

原理也不復雜。就是用Path 定義個圓型的軌跡。不停的獲取該圓形的軌跡的xy座標。

黑色圓 執行在該path 的上半圓。空心圓執行在該Path的下半圓。

如 圖如下:

alter

初始化

根據個資料準備好圓形。

public class AlterCircleView extends BaseView {
    private int mNumber = 5;
//--------------------------------------------------------------
    // 圓 屬性
    private int mRadius = DisplayUtils.dp2px(this.getContext(), 10);
    // 交替的兩個圓
    private Circle mCurrCircle, mNextCircle;
    private Circle[] mCircles = new Circle[mNumber];
    private List<Path> mPaths = new ArrayList<>();
//--------------------------------------------------------------
    // 測量 圍繞的中心圓 屬性
    float distance = 0.0f;
    float pos[] = new float[2];
    float tan[] = new float[2];
    // 測量圓的measure
    private PathMeasure measure;
    // 指定當前第幾個 圓Path 總數為 number-1
    private int index = 0;
//--------------------------------------------------------------
    // 黑色圓形, 去為 false  ,回來 為 true
    private boolean mBack = false;

    public AlterCircleView(Context context) {
        this(context, null);
    }
    public AlterCircleView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public AlterCircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        List<Circle> list = new CircleFactory(mRadius).generateCircles(mNumber);
        for (int i = 0; i < list.size(); i++) {
            mCircles[i] = list.get(i);
        }
        mCurrCircle = mCircles[0]; // 黑色圓
        mNextCircle = mCircles[1];
        measure = new PathMeasure();
    }
複製程式碼

測量

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        int measuredWidth = width, measuredHeight = height;

        if (widthMode != MeasureSpec.EXACTLY) {
            measuredWidth = mRadius * 2 * mNumber + mRadius * (mNumber - 1) + mMargin * 2 + mPadding * 2;
        }
        if (heightMode != MeasureSpec.EXACTLY) {
            // 當兩個圓,交替到 垂直狀態,+ 2個半徑 也就是 最大的高度。
            int r = mNextCircle.getX() - mCurrCircle.getX();
            measuredHeight = r + mRadius * 2 + mMargin + mPadding;
        }
        setMeasuredDimension(measuredWidth, measuredHeight);
    }
複製程式碼

旋轉圓的Path

測量完成,也就是說所有的資料已經準備好,然後在該方法中初始化 mNumber-1 個旋轉圓的Path

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 兩個圓形 中間的 旋轉圓,Path 路徑
        for (int i = 0; i < mCircles.length - 1; i++) {
            Circle currCircle = mCircles[i];
            Circle nextCircle = mCircles[i + 1];
            int r = (nextCircle.getX() + currCircle.getX()) / 2;
            int radius = r - currCircle.getX();
            Path path = new Path();
            path.addCircle(r, 0, radius, Path.Direction.CW);
            mPaths.add(path);
        }
    }
複製程式碼

繪製以及處理邏輯

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mMargin + mPadding + mRadius, mViewHeight / 2);
        canvas.save();
        for (Circle c : mCircles) {
            boolean solid = c.getSolid();
            mPaint.setStyle(Paint.Style.STROKE);
            if (solid)
                mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            canvas.drawCircle(c.getX(), c.getY(), c.getRadius(), mPaint);
        }
        // index 來 設定 要 測量的path
        measure.setPath(mPaths.get(index), false);
        // 獲取當前 點的 xy座標,以及正切(此處沒用)
        measure.getPosTan(distance, pos, tan);

        mNextCircle.setX((int) pos[0]);
        mNextCircle.setY((int) pos[1]);
複製程式碼

黑色圓-去: distance 初始化值為0.位置為圓心右手邊。
mNextCircle圓形跟隨該路徑移動至180度位置。
然後,黑色圓形則從180度的位置+distance開始移動至360/0度的位置。

黑色圓-回: 同理。

        //黑色圓-去:
        if (!mBack) {
            if (distance < measure.getLength() / 2) {
                float f = measure.getLength() / 2 + distance;
                float pos[] = new float[2];
                float tan[] = new float[2];
                measure.getPosTan(f, pos, tan);
                mCurrCircle.setX((int) pos[0]);
                mCurrCircle.setY((int) pos[1]);
                distance += 2;
            } else {
                // 交換2個圓位置
                Circle temp = mCircles[index];
                mCircles[index] = mCircles[index + 1];
                mCircles[index + 1] = temp;
                if (index < mPaths.size() - 1) {
                    index++;
                    distance = 0;
                    mCurrCircle = mCircles[index];
                    mNextCircle = mCircles[index + 1];
                } else {
                    distance = measure.getLength() / 2;
                    mBack = true;
                }
            }

        }
      //黑色圓-回:
      else {
            if (distance < measure.getLength()) {
                float f = distance - measure.getLength() / 2;
                float pos[] = new float[2];
                float tan[] = new float[2];
                measure.getPosTan(f, pos, tan);
                mCurrCircle.setX((int) pos[0]);
                mCurrCircle.setY((int) pos[1]);
                distance += 2;
            } else {
                Circle temp = mCircles[index];
                mCircles[index] = mCircles[index + 1];
                mCircles[index + 1] = temp;
                if (index > 0) {
                    index--;
                    distance = measure.getLength() / 2;
                    mCurrCircle = mCircles[index + 1];
                    mNextCircle = mCircles[index];
                } else {
                    distance = 0;
                    mBack = false;
                }
            }

        }
        postInvalidate();
        canvas.restore();
    }
}
複製程式碼

src下載

相關文章