Android自定义圆形进度条学习

Android中圆形进度条的应用还是挺多的,最近学习实现了圆形进度条。


RingProgressBar

meizu style
思路

要实现圆形进度条,

首先要画灰色背景圆环
再画蓝色进度圆环
再画进度数字

搞定。

首先自定义各种属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RingProgressBar">
        <attr name="ringColor" format="color" />
        <attr name="ringProgressColor" format="color" />
        <attr name="textColor" format="color" />
        <attr name="ringWidth" format="dimension" />
        <attr name="textSize" format="dimension" />
        <attr name="max" format="integer" />
        <attr name="showTextProgress" format="boolean" />
        <attr name="style">
            <enum name="STROKE" value="0" />
            <enum name="FULL" value="1" />
        </attr>
    </declare-styleable>
</resources>
初始化各种属性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RingProgressBar);
        ringColor = typedArray.getColor(R.styleable.RingProgressBar_ringColor, Color.GRAY);
        ringProgressColor = typedArray.getColor(R.styleable.RingProgressBar_ringProgressColor, Color.GREEN);
        textColor = typedArray.getColor(R.styleable.RingProgressBar_textColor, Color.GREEN);
        textSize = typedArray.getDimension(R.styleable.RingProgressBar_textSize, 16);
        ringWidth = typedArray.getDimension(R.styleable.RingProgressBar_ringWidth, 5);
        max = typedArray.getInteger(R.styleable.RingProgressBar_max, 100);
        textIsDisplayable = typedArray.getBoolean(R.styleable.RingProgressBar_showTextProgress, true);
        style = typedArray.getInt(R.styleable.RingProgressBar_style, 0);
        //资源回收
        typedArray.recycle();
初始化三种画笔
        //背景圆环画笔
        ringPaint = new Paint();
        ringPaint.setColor(ringColor);
        ringPaint.setStyle(Paint.Style.STROKE);
        ringPaint.setStrokeWidth(ringWidth);
        ringPaint.setAntiAlias(true);

        //进度圆环画笔
        ringProgressPaint = new Paint();
        ringProgressPaint.setColor(ringProgressColor);
        ringProgressPaint.setStrokeWidth(ringWidth);
        ringProgressPaint.setStrokeCap(Paint.Cap.ROUND);
        ringProgressPaint.setAntiAlias(true);
        switch (style) {
            case STROKE:
                ringProgressPaint.setStyle(Paint.Style.STROKE);
                break;
            case FULL:
                ringProgressPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                break;
        }

        //进度文字画笔
        textPaint = new Paint();
        textPaint.setColor(textColor);
        textPaint.setTextSize(textSize);
        textPaint.setTypeface(Typeface.DEFAULT_BOLD);
抗锯齿
        ringPaint.setAntiAlias(true);
圆形线条
        ringProgressPaint.setStrokeCap(Paint.Cap.ROUND);
圆环整体图
圆环整体图
画背景圆环
        int xCenter = getWidth() / 2;
        int yCenter = getHeight() / 2;

        int radius = (int) (xCenter - ringWidth / 2);
        canvas.drawCircle(xCenter, yCenter, radius, ringPaint);

xCenter:圆心横坐标
yCenter:圆心纵坐标
radius:半径
ringPaint:画笔

疑惑

这里我有点疑惑,为什么半径是xCenter - ringWidth / 2呢?
我认为半径应该是xCenter - ringWidth才对,很合理,宽度的一半减去线条宽度,刚好是圆环的半径。
怀着疑惑的心情画了上图,这里减去圆环线条宽度的一半或许是因为线条的宽度不可忽略,姑且这样认为吧,如果有大神看到希望指点迷津。

画进度圆环
        RectF rectF = new RectF(xCenter - radius, yCenter - radius, xCenter + radius, yCenter + radius);
        switch (style) {
            case STROKE:
                /*canvas.drawArc(rectF, 90, progress * 180 / max, false, ringProgressPaint);
                canvas.drawArc(rectF, 90, -progress * 180 / max, false, ringProgressPaint);*/
                canvas.drawArc(rectF, -90, progress * 360 / max, false, ringProgressPaint);
                break;
            case FULL:
                if (progress != 0) {
                    canvas.drawArc(rectF, -90, progress * 360 / 100, true, ringProgressPaint);
                }
                break;
        }
左上右下
        RectF rectF = new RectF(xCenter - radius, yCenter - radius, xCenter + radius, yCenter + radius);

xCenter - radius:矩形距离左边的距离
yCenter - radius:矩形距离上边的距离
xCenter + radius:矩形距离右边的距离
yCenter + radius:矩形距离下边的距离
其实可以理解为矩形左上角的坐标和右下角的坐标

画圆弧
        canvas.drawArc(rectF, -90, progress * 360 / max, false, ringProgressPaint);

rectF:圆弧在这个矩形中绘制
-90:圆弧顺时针绘制的开始角度
progress * 360 / max:圆弧绘制的角度
false:绘制时是否经过圆心,当style设置为STROKE时,是没有效果的,这里借用两张图片,简单明了
当style设置为FULL,这里设置为false时


false

当style设置为FULL,这里设置为true时


true

ringProgressPaint:画笔
魅族应用市场下载效果
meizu
        canvas.drawArc(rectF, 90, progress * 180 / max, false, ringProgressPaint);
        canvas.drawArc(rectF, 90, -progress * 180 / max, false, ringProgressPaint);

将进度分两次绘制,从底部同时向上绘制进度的一半,就达到了这个效果。

画进度数字
        String text = progress + "%";
        float textWidth = textPaint.measureText(text, 0, text.length());
        if (showTextProgress && progress != 0 && style == STROKE) {
            canvas.drawText(text, xCenter - textWidth / 2, yCenter + textSize / 2, textPaint);
        }
RingProgressBar
package com.goldou.ringprogressbar;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by Administrator on 2017.10.30  0030.
 */

public class RingProgressBar extends View {

    private Paint ringPaint;
    private Paint ringProgressPaint;
    private Paint textPaint;

    private int ringColor;
    private int ringProgressColor;
    private int textColor;

    private float textSize;
    private float ringWidth;

    private int max;
    private int progress;

    private boolean showTextProgress;
    private int style;
    private final int STROKE = 0;
    private final int FULL = 1;

    private Context context;

    public RingProgressBar(Context context) {
        this(context, null);
    }

    public RingProgressBar(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RingProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        initAttrs(context, attrs);
        initPaint();
    }

    private void initPaint() {
        ringPaint = new Paint();
        ringPaint.setColor(ringColor);
        ringPaint.setStyle(Paint.Style.STROKE);
        ringPaint.setStrokeWidth(ringWidth);
        ringPaint.setAntiAlias(true);

        ringProgressPaint = new Paint();
        ringProgressPaint.setColor(ringProgressColor);
        ringProgressPaint.setStrokeWidth(ringWidth);
        ringProgressPaint.setStrokeCap(Paint.Cap.ROUND);
        ringProgressPaint.setAntiAlias(true);
        switch (style) {
            case STROKE:
                ringProgressPaint.setStyle(Paint.Style.STROKE);
                break;
            case FULL:
                ringProgressPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                break;
        }

        textPaint = new Paint();
        textPaint.setColor(textColor);
        textPaint.setTextSize(textSize);
        textPaint.setTypeface(Typeface.DEFAULT_BOLD);
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RingProgressBar);
        ringColor = typedArray.getColor(R.styleable.RingProgressBar_ringColor, Color.GRAY);
        ringProgressColor = typedArray.getColor(R.styleable.RingProgressBar_ringProgressColor, Color.GREEN);
        textColor = typedArray.getColor(R.styleable.RingProgressBar_textColor, Color.GREEN);
        textSize = typedArray.getDimension(R.styleable.RingProgressBar_textSize, 16);
        ringWidth = typedArray.getDimension(R.styleable.RingProgressBar_ringWidth, 5);
        max = typedArray.getInteger(R.styleable.RingProgressBar_max, 100);
        showTextProgress = typedArray.getBoolean(R.styleable.RingProgressBar_showTextProgress, true);
        style = typedArray.getInt(R.styleable.RingProgressBar_style, 0);
        //资源回收
        typedArray.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int xCenter = getWidth() / 2;
        int yCenter = getHeight() / 2;

        int radius = (int) (xCenter - ringWidth / 2);
        canvas.drawCircle(xCenter, yCenter, radius, ringPaint);

        RectF rectF = new RectF(xCenter - radius, yCenter - radius, xCenter + radius, yCenter + radius);
        switch (style) {
            case STROKE:
                /*canvas.drawArc(rectF, 90, progress * 180 / max, false, ringProgressPaint);
                canvas.drawArc(rectF, 90, -progress * 180 / max, false, ringProgressPaint);*/
                canvas.drawArc(rectF, -90, progress * 360 / max, false, ringProgressPaint);
                break;
            case FULL:
                if (progress != 0) {
                    canvas.drawArc(rectF, -90, progress * 360 / 100, true, ringProgressPaint);
                }
                break;
        }

        String text = progress + "%";
        float textWidth = textPaint.measureText(text, 0, text.length());
        if (showTextProgress && progress != 0 && style == STROKE) {
            canvas.drawText(text, xCenter - textWidth / 2, yCenter + textSize / 2, textPaint);
        }
    }

    public synchronized int getMax() {
        return max;
    }

    public synchronized void setMax(int max) {
        if (max < 0) {
            throw new IllegalArgumentException("max not less than 0");
        }
        this.max = max;
    }

    public synchronized int getProgress() {
        return progress;
    }

    public synchronized void setProgress(int progress) {
        if (progress < 0) {
            throw new IllegalArgumentException("progress not less than 0");
        }
        if (progress > max) {
            progress = max;
        }
        if (progress <= max) {
            this.progress = progress;
            postInvalidate();
        }
    }

    public int getRingColor() {
        return ringColor;
    }

    public void setRingColor(int ringColor) {
        this.ringColor = ringColor;
    }

    public int getRingProgressColor() {
        return ringProgressColor;
    }

    public void setRingProgressColor(int ringProgressColor) {
        this.ringProgressColor = ringProgressColor;
    }

    public int getTextColor() {
        return textColor;
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    public float getTextSize() {
        return textSize;
    }

    public void setTextSize(float textSize) {
        this.textSize = textSize;
    }

    public float getRingWidth() {
        return ringWidth;
    }

    public void setRingWidth(float roundWidth) {
        this.ringWidth = roundWidth;
    }
}
最后

有什么解释不对还望各位大神指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容