Android自定义圆形进度条学习

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

《Android自定义圆形进度条学习》 RingProgressBar

《Android自定义圆形进度条学习》 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);
圆环整体图

《Android自定义圆形进度条学习》 圆环整体图

画背景圆环
        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时

《Android自定义圆形进度条学习》 false

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

《Android自定义圆形进度条学习》 true

ringProgressPaint:画笔

魅族应用市场下载效果

《Android自定义圆形进度条学习》 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;
    }
}
最后

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

    原文作者:Gentleman1995
    原文地址: https://www.jianshu.com/p/bcc3addeb737
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞