Circle Progress 实现原理

泡在网上的日子 / 文 发表于2015-04-26 23:46 第次阅读 Progress

原文:http://fichardu.github.io/blog/circle-progress-view/ 

记得看过上面的一个动画设计,就试着实现了一下,首先是可以看到这个动画由两部分组成,一个圆圈的顺时针转动,另一个是圆点的直线运动,圆点之间有时间差,两种运动叠加就形成了这种滚动的效果。

图一、图二、图三

上面图一显示了只有圆圈旋转的状态,图二是只有圆点直线运动的状态,图三是图二中各个圆点添加时间差后的效果。

实现

绘制点

这里一共有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



收藏 赞 (0) 踩 (0)
上一篇:深入浅出RxJava四-在Android中使用响应式编程
原文链接 http://blog.danlew.net/2014/10/08/grokking-rxjava-part-4/ 译文链接 http://blog.csdn.net/lzyzsd/article/details/45033611 在第 1 , 2 , 3 篇中,我大概介绍了RxJava是怎么使用的。下面我会介绍如何在Android中使用RxJava. RxAndroid RxAndr
下一篇: Android加载不同DPI资源与内存消耗之间的关系
原文 http://dwz.cn/HZbpZ Android DPI 分级标准简介 Android 设备在物理尺寸和屏幕密度上都有很大的不同,为了简化多设备的设计方案,就是设定一套分级标准。屏幕密度上的分级标准就是:LDPI、MDPI、HDPI、XHDPI,也就是各种大小的 DPI(Dots per inch)。 DP