自定义CircleProgressBar

本文介绍了如何自定义一个实线分数进度展示的CircleProgressBar。详细阐述了实现过程,包括onMeasure()和onDraw()方法的使用,颜色渐变的Shader渲染,以及通过线程动态更新进度和数字的方法。此外,还探讨了圆弧的绘制原理,如何确定椭圆大小位置并绘制360度圆弧。
摘要由CSDN通过智能技术生成

概述

这是一个自定义实线分数,进度展示的progressBar。
实现的效果差强人意,但我们可以一起探究下自定义控件的过程。
除此之外,我发现绘制弧线的过程,相对于绘制其他的图形,是比较难以理解的。我后面总结下绘制弧线的过程。

效果图

因为第一次做gif图形,效果不好。其实图形的变化是连贯的。
1. 实线实现的效果
实线
2. 虚线实线的效果
虚线

实现过程分析

1.自定义控件,有两个方法几乎是必写的,那就是onMeasure(int widthMeasureSpec, int heightMeasureSpec)和onDraw(Canvas canvas)方法。
onMeasure()方法实现测量。如果我们直接将控件的大小给一个确定值或者match_parent,就可以不用重写该方法。
如果我们将控件的宽高属性设置为wrap_content,那么我们就必须重写该方法了,毕竟,若你不告诉系统,系统怎么会知道这个content是多大呢。

    /**
     * 如果测量模式不是EXACTLY(即精确测量),我们就将该View的长和宽都设置为250dp。
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int viewWidth,viewHeight;

        /**
         * 设置宽度
         * 获取测量模式和测量的大小
         */
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);
        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
        {

            viewWidth = specSize;
        } else{
            /**
             * 如果view直接赋值为250,则是250px,通过下面的代码,将sp转化为dip(dp).
             */
            viewWidth=(int)(2*TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,250,getResources().getDisplayMetrics()));
        }

        /**
         * 设置高度
         */
        specMode = MeasureSpec.getMode(heightMeasureSpec);
        specSize = MeasureSpec.getSize(heightMeasureSpec);
        if (specMode == MeasureSpec.EXACTLY)// match_parent , accurate
        {

            viewHeight = specSize;
            Log.d("liang","viewHeight"+viewHeight);
        } else{
            viewHeight=(int)(2*TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,250,getResources().getDisplayMetrics()));
        }

        setMeasuredDimension(viewWidth, viewHeight);

    }

onDraw()方法是绘制图形的时候调用的方法。我们需要绘制的元素有三个,圆弧(实现或者虚线),图片,分数。
在绘制过程中,需要实现颜色渐变的效果。我们借助Shader进行渲染。

 mLinearGradient1 = new LinearGradient(0, 0, 0, 2*radius, new int[] {
                firstColor, secondColor, thirdColor }, null,
                Shader.TileMode.CLAMP);

mPaint.setShader(mLinearGradient1);

数组前的四个参数确定渲染的范围,int数组里面的三个元素是渐变的颜色。最后一个参数是渲染模式,感兴趣的读者可以自行查询LinearGradient的用法,这里不做过多的表述。

整个onDraw()方法的代码段:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint.setShader(mLinearGradient1);
        RectF rectF=new RectF(50,50,2*radius,2*radius);
        //Rect rect=new Rect(50,50,2*radius,2*radius);
        //canvas.drawRect(rect,mPaint);
        mPaint.setColor(Color.BLUE);
        canvas.drawArc(rectF,-90,progress,false,mPaint);

        Paint paint=new Paint();
        paint.setColor(textColor);
        paint.setTextAlign(Paint.Align.CENTER);
        paint.setTextSize(textSize);
        paint.setSubpixelText(false);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();

        float y = radius - fontMetrics.descent + (fontMetrics.bottom - fontMetrics.top) / 2;

        int margin=(int)(radius*0.2);
        int offest=(int)(radius*0.28);

        Rect rect1=new Rect(radius-margin,radius-margin-offest,
                radius+margin,radius+margin-offest);
        canvas.drawBitmap(icon,null,rect1,paint);
        canvas.drawText(grade2+"",radius,y+70,paint);

    }

2.进度和数字变化
为了实现进度和数字变化,这里开了两个线程。并且在每个线程里面用postInvalidate()更新画布。
为了实现这个功能,我首先记录了圆弧画完一圈所用的时间,然后用这一圈所花费的时间除以分数的最大值,所得的结果就是每次更新分数所需要的时间。
这么说太过抽象,还是看代码吧:

    private int progress=0;
    /**
     * 绘制的速度
     */
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值