自定義控件之帶漸變色的圓形進度條

微信公衆號

七夕到了,祝大家七夕節快樂!
今天給大家講解一個簡單的進度條的自定義。首頁呢,我們參考咪咕善跑APP的效果:
 

演示圖

. 分析

從上面的效果圖看呢,進度條的漸變色主要是在三個顏色上進行漸變。那我們先定義好三個漸變的顏色:

1private int colorGreen = 0xff16FCD7;
2private int colorYellow = 0xffFECB55;
3private int colorRed = 0xffFF0054;

然後我們看到進度條的頭是圓角的,所以我們會用到:

1circlePaint.setStrokeCap(Paint.Cap.ROUND);

顯然整個進度的繪製就是在canvas上畫弧的過程,只要我們進度的數據算出需要畫的弧度然後配上動畫效果基本上就能完成了。

. 實踐

我們主要看畫的邏輯和動畫的邏輯就可以了。
先看下在畫布上畫弧和文字的過程:

 1    @Override
 2    protected void onDraw(Canvas canvas) {
 3        super.onDraw(canvas);
 4        mPaint.setStyle(Paint.Style.STROKE);
 5        mPaint.setStrokeWidth(mPaintWidth);
 6        mPaint.setStrokeCap(Paint.Cap.ROUND);
 7        mPaint.setColor(mBackgroundColor);
 8        circlePaint.setStyle(Paint.Style.STROKE);
 9        circlePaint.setStrokeWidth(mPaintWidth);
10        circlePaint.setStrokeCap(Paint.Cap.ROUND);
11        circleBackgroundPaint.setStyle(Paint.Style.STROKE);
12        circleBackgroundPaint.setStrokeWidth(mPaintWidth / 2.0f);
13        circleBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
14        circleBackgroundPaint.setShader(radialGradient);
15        mPaint.setColor(mProgressColor);
16        if (isOver) {
17            canvas.drawArc(rectF, -90, mBackgroundSweepAngle, false, circlePaint);
18            mPaint.setColor(mOverProgressColor);
19            canvas.drawArc(rectF, -90, 360, false, mPaint);
20        } else {
21            circlePaint.setShader(sweepGradient);
22            if (mProgressSweepAngle == 360) {
23                canvas.drawArc(rectF, -88, 355, false, circlePaint);
24            } else {
25                canvas.drawArc(rectF, -88, mProgressSweepAngle, false, circlePaint);
26            }
27        }
28
29        if (!isHideCenterText) {
30            // 畫中間數字
31            mPaint.setColor(mTextColor);
32            mPaint.setTextSize(DisplayUtils.sp2px(34));
33            mPaint.setStyle(Paint.Style.FILL);
34            mPaint.setTextAlign(Paint.Align.CENTER);
35            Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
36            float bottom = fontMetrics.bottom;
37            int baseLineY = (int) (mHeight / 2 + mPaint.getTextSize() / 2 - bottom);
38            if (Long.valueOf(mNumber) == mTotalKcal
39                    && mTakeKcal > mTotalKcal) {
40                mNumber = String.valueOf(mTakeKcal);
41            }
42            canvas.drawText(mNumber, mWidth / 2 - offSet, baseLineY, mPaint);
43            mTextPaint.setColor(mTextColor);
44            mTextPaint.setTextSize(DisplayUtils.sp2px(11));
45            mTextPaint.setTextAlign(Paint.Align.CENTER);
46            mTextPaint.setStyle(Paint.Style.FILL);
47            int topBaseLineY = (int) (mHeight / 2 - mPaint.getTextSize() / 2 - DisplayUtils.dp2px(19));
48            if (isOver) {
49                canvas.drawText("多吃了/千卡", mWidth / 2 - offSet, topBaseLineY, mTextPaint);
50            } else {
51                canvas.drawText("還可以吃/千卡", mWidth / 2 - offSet, topBaseLineY, mTextPaint);
52            }
53            mTextPaint.setColor(mSmallTextColor);
54            mTextPaint.setTextSize(DisplayUtils.sp2px(9));
55            int bottomBaseLineY = (int) (mHeight / 2 + mPaint.getTextSize() / 2 + DisplayUtils.dp2px(25));
56            canvas.drawText("預算: " + mTotalKcal, mWidth / 2 - offSet, bottomBaseLineY, mTextPaint);
57        }
58    }

實現漸變效果的呢就是通過下面的API:

1sweepGradient = new SweepGradient(mWidth / 2, mHeight / 2, colors, positions);
2circlePaint.setShader(sweepGradient);

然後我們用屬性動畫來做動畫效果:

 1/**
 2     * @param current  消耗的卡路里所佔的比例(消耗的/總的預算 * 360)
 3     *               或者
 4     *               超出的卡路里
 5     * @param isOver 是否超出預算
 6     */
 7    private void setAnimation(int current, boolean isOver) {
 8        this.isOver = isOver;
 9        ValueAnimator progressAnimator = ValueAnimator.ofInt(0, current);
10        progressAnimator.setDuration(2000);
11        progressAnimator.setTarget(mProgressSweepAngle);
12        progressAnimator.addUpdateListener(animation -> {
13            mProgressSweepAngle = ((int) animation.getAnimatedValue());
14            if (isOver) {
15                // 超出部分直接繪製進度條
16                mNumber = String.valueOf(mTotalKcal * mProgressSweepAngle / 360);
17                if (Integer.valueOf(mNumber) > mTakeKcal
18                        || mProgressSweepAngle == mProgressSweepAngleTotal) {
19                    mNumber = String.valueOf(mTakeKcal);
20                }
21            } else {
22                // 剩餘部分作差繪製
23                mNumber = String.valueOf(mTotalKcal - mTotalKcal * mProgressSweepAngle / 360);
24                if (Integer.valueOf(mNumber) > (mTotalKcal - mTakeKcal)
25                        || mProgressSweepAngle == mProgressSweepAngleTotal) {
26                    mNumber = String.valueOf(mTotalKcal - mTakeKcal);
27                }
28            }
29            postInvalidate();
30        });
31        progressAnimator.start();
32    }

完整代碼請微信搜索公衆號:“南京Android部落” 後臺私信郵箱地址獲取哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章