自定义圆形进度条实现动态显示指定进度

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiaoyantan/article/details/53149824

你是否想实现显示待文字的圆形进度条?
首先得写一个类RoundProgress继承View,重写其中onMeasure()和onDraw()方法。在onMeasure()里获取当前画布的宽度。
在onDraw()方法里主要绘制如下三部分:

  • 绘制圆环
  • 绘制圆弧
  • 绘制文本

相关属性如下:

 /**
     * 圆环的颜色
     */
    private int ringColor;
    //    圆环进度的颜色
    private int ringProgressColor;
    //    圆环的宽度
    private int ringWidth;
    //    字体大小
    private int textSize;
    //    字体颜色
    private int textColor ;
    //    画笔
    private Paint paint;
    //    得到控件宽度
    private int width;
    //    最大进度
    private int max;
    //    当前进度
    private int progress;

在绘制之前我们应该先明白相关坐标,如下图:

这里写图片描述

  • 圆环的圆心坐标: x , y都是画布宽度的一半width/2,width/2,半径是画布宽度的一半 减去圆环宽度的一半radius = width/2 - roundWidth/2;

绘制圆环的代码如下:

//        圆心坐标和半径
        float circleX = width / 2;
        float circleY = width / 2;
        float radius = width / 2 - ringWidth / 2;
//       1、 绘制圆环
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(ringWidth);
        paint.setColor(ringColor);
        canvas.drawCircle(circleX, circleY, radius, paint);
  • 绘制圆弧的边界应该也能看图得出来,代码如下:
//       2、 绘制圆弧
        RectF oval = new RectF(ringWidth / 2, ringWidth / 2, width - ringWidth / 2, width - ringWidth / 2);
        paint.setColor(ringProgressColor);
        canvas.drawArc(oval, 0, progress * 360 / max, false, paint);
  • 绘制文本,首先根据指定文本得到包裹文本的矩形大小,然后在指定位置开始绘制文本。这里要注意的是:文本是从左下角开始绘制的,位置见上图中的textX,textY;还有一定要将绘制圆环时的画笔宽度设置为0.具体代码:
//        3、绘制文本
        String text = progress * 100 / max + "%";
        paint.setColor(textColor);
        paint.setTextSize(textSize);
//        注意此处一定要重新设置宽度为0
        paint.setStrokeWidth(0);
//        得到指定文本的边界矩形大小
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
        canvas.drawText(text, width / 2 - bounds.width() / 2, width / 2 + bounds.height() / 2, paint);

为了更方便的使用这个RoundProgress控件,我们应该自定义相关属性attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RoundProgress">
        <attr name="ringColor" format="color"></attr>
        <attr name="ringProgressColor" format="color"></attr>
        <attr name="ringWidth" format="dimension"></attr>
        <attr name="textSize" format="dimension"></attr>
        <attr name="textColor" format="color"></attr>
        <attr name="max" format="integer"></attr>
        <attr name="progress" format="integer"></attr>
    </declare-styleable>
</resources>

在构造方法中初始化画笔并得到布局文件中的相关属性。这里顺便提一下三个构造方法的作用,第一个用于java代码创建对象,第二个用于布局文件加载该View,必须有,不然会崩溃。

 /**
     * 此构造方法用于java代码创建对象
     * @param context
     */
    public RoundProgress(Context context) {
        this(context, null);
    }

    /**
     * 此构造方法用于布局文件加载该View,必须有,不然会崩溃
     * @param context
     * @param attrs
     */
    public RoundProgress(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint();
//        设置抗锯齿
        paint.setAntiAlias(true);
//        得到所有自定义属性的数组
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RoundProgress);
        ringColor = typedArray.getColor(R.styleable.RoundProgress_ringColor,Color.GRAY);
        ringProgressColor = typedArray.getColor(R.styleable.RoundProgress_ringProgressColor, Color.RED);
        ringWidth = (int) typedArray.getDimension(R.styleable.RoundProgress_ringWidth,UIUtils.dip2px(10));
        textSize = (int) typedArray.getDimension(R.styleable.RoundProgress_textSize,UIUtils.dip2px(20));
        textColor = typedArray.getColor(R.styleable.RoundProgress_textColor,Color.RED);
        max = typedArray.getInteger(R.styleable.RoundProgress_max,100);
        progress = typedArray.getInteger(R.styleable.RoundProgress_progress,60);
//        不要忘记回收
        typedArray.recycle();
    }

在布局文件中使用这个自定义View.

 <com.example.txy.example.view.RoundProgress
            android:id="@+id/rp_home"
            app:ringColor="@android:color/darker_gray"
            app:ringProgressColor="@android:color/holo_red_dark"
            app:ringWidth="10dp"
            app:textSize="20sp"
            app:textColor="@color/text_progress"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:layout_width="120dp"
            android:layout_height="120dp" />

使进度条动态加载显示的代码:

 totalProgress = 90;
//        让当前的进度条动态的加载显示
        new Thread(new Runnable() {
            @Override
            public void run() {
                rp_home.setMax(100);
                rp_home.setProgress(0);
                for(int i = 0; i < totalProgress; i++) {
                    rp_home.setProgress(rp_home.getProgress() + 1);
                    SystemClock.sleep(30);
//                    强制重绘 Use this to invalidate the View from a non-UI thread
                    rp_home.postInvalidate();
                }
            }
        }).start();

github代码链接:https://github.com/18895612697/RoundProgressMaster
希望对大家有帮助

猜你喜欢

转载自blog.csdn.net/xiaoyantan/article/details/53149824