自定义圆形进度条

实现效果
这里写图片描述
实现思路:
1.绘制背景圆形
2.绘制中间文字进度,需要计算文字绘制的起点,保证文字在控件的中心,这里用到了measureText()方法对文字宽度进行测量,文字绘制是从基线开始绘制,所以要通过FontMetrics来计算文字文字y坐标上的位置才能放在中间显示(具体计算参考代码)
3.绘制进度圆弧, 圆弧起点角度固定,通过显示进度值动态改变圆弧的结束角度来绘制圆弧

注意:要将文字绘制在圆的终点需要计算文字基线值
可以通过Paint.FontMetricsInt(Paint.FontMetrics)获取top,ascent,desent, bottom, leading这几个属性
在这里插入图片描述
它们的值都是相对于baseline的距离
top = top线的y坐标 - baseline线的y坐标
bottom = bottom线的y坐标 - baseline线的y坐标
ascent = ascent线的y坐标 - baseline线的y坐标
desent = desent线的y坐标 - baseline线的y坐标
计算baseline的值:
baseline = center +(FontMetrics.bottom - FontMetrics.top)/2 - FontMetrics.bottom
一.自定义View代码

public class CircleProgressBar extends View {

    private Paint paintOne;//绘制背景
    private Paint paintTwo;//绘制文字
    private Paint paintThree;//绘制进度

    private int progressWidth=20;//进度宽度
    private int backgroundColor=Color.LTGRAY;//背景色
    private int progressColor=Color.DKGRAY;//进度色
    private int progressTextColor=Color.BLACK;//进度文字颜色
    private int progressTextSize=50;//进度文字大小
    private int progress;//进度值
    private int startDegree;//进度开始显示角度

    private int radius=50;//半径
    private int centerX;//圆心x坐标
    private int centerY;//圆心y坐标
    private int endDegree;//结束的角度值
    public CircleProgressBar(Context context) {
        this(context,null);
    }

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

    public CircleProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //获取xml文件中中自定义属性值
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.CircleProgressBar);
        progressWidth=typedArray.getDimensionPixelSize(R.styleable.CircleProgressBar_progressWidth,20);
        backgroundColor=typedArray.getColor(R.styleable.CircleProgressBar_backgroundColor,Color.LTGRAY);
        progressColor=typedArray.getColor(R.styleable.CircleProgressBar_progressColor,Color.DKGRAY);
        progressTextColor=typedArray.getColor(R.styleable.CircleProgressBar_progressTextColor,Color.BLACK);
        progressTextSize=typedArray.getDimensionPixelSize(R.styleable.CircleProgressBar_progressTextSize,50);
        progress=typedArray.getInteger(R.styleable.CircleProgressBar_progress,0);
        startDegree=typedArray.getInteger(R.styleable.CircleProgressBar_startDegree,0);
        typedArray.recycle();
        //初始化画笔
        initPaint();
    }
    private void initPaint(){
        //绘制背景
        paintOne=new Paint();
        paintOne.setAntiAlias(true);//抗锯齿使图形更圆滑
        paintOne.setStrokeWidth(progressWidth);//画笔宽度
        paintOne.setStyle(Paint.Style.STROKE);//设置画笔描边
        paintOne.setColor(backgroundColor);//设置颜色
        //绘制文字进度
        paintTwo=new Paint();
        paintTwo.setTextSize(progressTextSize);//设置画笔大小
        paintTwo.setStyle(Paint.Style.FILL);//设置画笔填充
        paintTwo.setColor(progressTextColor);
        //绘制进度
        paintThree=new Paint();
        paintThree.setAntiAlias(true);
        paintThree.setStrokeWidth(progressWidth);
        paintThree.setStyle(Paint.Style.STROKE);
        paintThree.setColor(progressColor);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //获取进度条圆心坐标
        centerX=getWidth()/2;
        centerY=getHeight()/2;
        //获取进度条半径,控件宽度/2减去进度条宽度
        radius=centerX-progressWidth;
        //绘制背景圆
        canvas.drawCircle(centerX,centerY,radius,paintOne);
        //绘制中间进度文字
        String text=progress+"%";
        Paint.FontMetrics metrics=paintTwo.getFontMetrics();
        //获取绘制文字的起点x,y坐标,保证文字在控件的中心显示
        float x=centerX-paintTwo.measureText(text)/2;
        float y=centerY+(metrics.bottom-metrics.top)/2-metrics.bottom;
        canvas.drawText(text,x,y,paintTwo);
        //绘制进度圆弧
        RectF rectF=new RectF(centerX-radius,centerY-radius,centerX+radius,centerY+radius);
        canvas.drawArc(rectF,startDegree,endDegree,false,paintThree);
    }

    /**
     * 更新进度条进度值,这里总值为100
     * @param progress 需要转换成以100为分母的进度
     */
    public void setProgress(int progress){
        this.progress=progress;
        if(progress<=100){
            //转换角度用于绘制圆弧
            endDegree=progress*360/100;
            //可在子线程重绘
            postInvalidate();
        }
    }
}

二,自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CircleProgressBar">
        <attr name="progressWidth" format="dimension"/>
        <attr name="backgroundColor" format="color"/>
        <attr name="progressColor" format="color"/>
        <attr name="progressTextColor" format="color"/>
        <attr name="progressTextSize" format="dimension"/>
        <attr name="progress" format="integer"/>
        <attr name="startDegree" format="integer"/>
    </declare-styleable>
</resources>

三,使用方法
可以在布局文件中设置进度宽度progressWidth,背景色backgroundColor,进度颜色progressColor,中间文字大小progressTextSize,中间文字颜色progressTextColor,进度开始的角度startDegree,当前进度progress;
也可以通过代码设置进度代码如下:

int progress;
CircleProgressBar progressBar = (CircleProgressBar) findViewById(R.id.progressBar);
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (progress < 100) {
                    progress+=5;
                    progressBar.setProgress(progress);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

xml布局中使用如下:

 <com.example.qdq.uidemo.CircleProgressBar
        android:id="@+id/progressBar"
        android:layout_width="100dp"
        android:layout_height="100dp"
        app:progressWidth="5dp"
        app:backgroundColor="@color/colorAccent"
        app:progressColor="@color/colorPrimary"
        app:progressTextColor="@color/colorPrimaryDark"
        app:progressTextSize="20sp"
        app:startDegree="-90"
        app:progress="1"/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值