android之自定义带文本的圆角进度条

自定义圆角进度条以及颜色渐变的进度条

先上图,给个直观印象



一、先来看看渐变的圆角


 private void init(AttributeSet attrs) {
        mRadius = (int) ((getScreenSize(context).x * 0.6f) / 2);//屏幕的1/4
        initPaint();
    }


    private void initPaint() {
        // 初始化画笔对象
        mPaint.setStyle(Style.STROKE);
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);//设置抖动
        mPaint.setStrokeCap(Cap.ROUND);

        mPaintUnReach.setStyle(Style.STROKE);
        mPaintUnReach.setAntiAlias(true);
        mPaintUnReach.setDither(true);
        mPaintUnReach.setStrokeCap(Cap.ROUND);
        // 设置画笔颜色和宽度
        mPaintUnReach.setColor(mUnReachBarColor);

        mTextPaint.setStyle(Style.FILL);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setDither(true);
    }
   1、初始化画笔及画圆的半径,半径非常重要,会影响圆的宽高,读者可根据自己需要提供一个公用方法设置或者自定义属性实现,现只是为了讲解,取屏幕w的1/4为半径
   2、初始化画笔,圆角主要是setStrokeCap(Cap.ROUND)来设置的,而设置抖动setDither()这个大概意思是保证画图的清晰度已经平滑度,抗锯齿setAntiAlias();表示画出来的视图不会有锯齿


二、再来看看其onMeasure和onDraw()方法:

      

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 两个画笔的最大宽度
        int paintWidth = Math.max(mUnReachBarWidth, mReachBarWidth);
        int wMode = MeasureSpec.getMode(widthMeasureSpec);
        int wSize = MeasureSpec.getSize(widthMeasureSpec);
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int hSize = MeasureSpec.getSize(heightMeasureSpec);

        if (wMode == MeasureSpec.AT_MOST && hMode == MeasureSpec.AT_MOST) {
            wSize = mRadius * 2 + (paintWidth / 2) * 2;
            hSize = mRadius * 2 + (paintWidth / 2) * 2;
        } else if (wMode == MeasureSpec.AT_MOST) {
            wSize = mRadius * 2 + (paintWidth / 2) * 2;
        } else if (hMode == MeasureSpec.AT_MOST) {
            hSize = mRadius * 2 + (paintWidth / 2) * 2;
        }
        if (0 >= wSize) {
            wSize = mRadius * 2;
        }

        if (0 >= hSize) {
            hSize = mRadius * 2;
        }

        // 获取宽度和高度的最小值,作为当前view的宽度和高度
        mSize = Math.min(wSize, hSize);
        // 设置进度条的大小:整个view的大小
        setMeasuredDimension(mSize, mSize);

        // 设置画笔宽度
        mMaxPaintWidth = paintWidth;
        // 计算进度条的半径 画笔是从画笔的宽度中间开始画的----
        // 、、此处有个坑,若是有进入到二级页面再回来,可能视图会变小,因为每次半径测量时都会减小,
        // 根据需要半径最好放在初始化时设置,不要让它变化
        mRadius = (mSize - (mMaxPaintWidth / 2) * 2) / 2;

        mPaint.setStrokeWidth(mMaxPaintWidth);
        mPaintUnReach.setStrokeWidth(mMaxPaintWidth);
    }

  @Override
    protected void onDraw(Canvas canvas) {
        // 在save和restore之间的代码可以进行canvas的平移、缩放等操作
        canvas.save();
        // 画布旋转120度
        canvas.rotate(115, mSize / 2, mSize / 2);
        int progressMax = getMax();
        // 绘制unreachedBar
        // 绘制reachBar :画布旋转115度,所以是从115度开始,从0开始,从 5度开始画,就是120
        canvas.drawArc(new RectF(mMaxPaintWidth / 2, mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2), 5, progressMax * 1.0f / progressMax * 300, false, mPaintUnReach);

//        canvas.drawCircle(mSize / 2, mSize / 2, mRadius, mPaintUnReach);
        // 设置画笔颜色:绘制过程中会渐变 mReachBarColor是数组起始颜色和最终颜色,渐变的过程
        SweepGradient sg = new SweepGradient(mSize / 2, mSize / 2, mReachBarColor, null);
        mPaint.setShader(sg);
//        sg.setLocalMatrix();除了旋转画布外,也可根据这个矩阵来旋转起始角度
        // 计算当前进度对应的角度
        float sweepAngle = mCurrentProgress * 1.0f / progressMax * 300;
        // 绘制reachBar :原始0度角是沿x轴方向的旋转115度之后,0角度指的就是115度的位置,
        // 起始角度为5是因为画弧度的颜色值是从一半开始画的,所以后一半圆会取前边的颜色值,导致不一致,所以从5度开始画,可根据画笔宽度的一半来设置
        canvas.drawArc(new RectF(mMaxPaintWidth / 2, mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2, mSize - mMaxPaintWidth / 2), 5, sweepAngle, false, mPaint);
        canvas.restore();
        drawText(canvas);
    }

    private void drawText(Canvas canvas) {
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTextSize(dp2px(40));
        mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);// 设置粗体
        float weightWidth = mTextPaint.measureText(weightValue);
        float weightTextSize = mTextPaint.getTextSize();
        canvas.drawText(weightValue, mSize / 2 - weightWidth / 2, mSize / 2 + weightTextSize / 2 - dp2px(5), mTextPaint);

        mTextPaint.setTypeface(Typeface.DEFAULT);//设置常规字体
        // 绘制单位(Kg)
        mTextPaint.setTextSize(dp2px(12));

        // 此处多减去了一个textSize的一半,因为绘制text的时候
        canvas.drawText(unit, mSize / 2 + weightWidth / 2, mSize / 2 + weightTextSize / 2 - dp2px(5), mTextPaint);

        // 绘制“体重状态”
        mTextPaint.setTextSize(dp2px(12));
        weightWidth = mTextPaint.measureText(weightStatus);
        // 以下也可以获取大小范围
//        mPaint.getTextBounds(text, 0, text.length(), mRect);//
//        int x = (getWidth() / 2) - mRect.centerX();// 文本的内容区域中心点开始绘制
//        int y = (getHeight() / 2) - mRect.centerY();
        float weightStatusTextSize = mTextPaint.getTextSize();
        canvas.drawText(weightStatus, mSize / 2 - weightWidth / 2, mSize / 2 - dp2px(12) - weightTextSize / 2, mTextPaint);

        // 绘制“体重目标”
        mTextPaint.setTextSize(dp2px(12));
        weightWidth = mTextPaint.measureText(weightTargetDesc);
        float targetTextSize = mTextPaint.getTextSize();
        canvas.drawText(weightTargetDesc, mSize / 2 - weightWidth / 2, mSize / 2 + weightTextSize, mTextPaint);
    }


   1、主要是测量视图的宽高,然后通过setMeasuredimension来设置其测量的宽高

          高能预警:此处有个坑,天大的坑  :mRadius 在这里不断的赋值,由于onMeasure不单单执行一次,在测量期间会执行多次,导致mRadius一直在变化,导致逐渐变小或变大,导致视图可能会变的更大或视图不可见,所以这种初始化的赋值,建议放在初始化或ondraw中,就不会有这种问题。。。这里出现问题就直接拿出来跟大家分享,代码我也没改正,圆角渐变代码我并没有改正,但是色环的已经改正了,代码都差不多,自行参考


  2、onDraw方法中 首先因为起始角度(0角度)是x轴方向,所以要旋转画布到自己所需要的开始绘制的地方,这里将画布旋转115,即绘制的起始点;此外由于画笔是从画笔的宽度中心点开始绘制的所以mRadius半径mSize减去画笔跨度的一半再除以2,就是画圆的半径 即(

mRadius = (mSize - (mMaxPaintWidth / 2) * 2) / 2
,而后drawArc就是画弧, 第一次调用就是画弧的背景,第二次才是画弧的进度,画弧的时候起始角度是从5开始,因为,画笔是从中间开始的,而由于是渐变色(SweepGradent类控制的)前一半圆弧的颜色是往前取的所以会导致有色差,所以起始角度往后一移动5个角度(可根据画笔宽度的一半来取),这也是为什么只旋转115而不是120角度的原因。


二、色环的代码跟圆弧的差不多,依葫芦画瓢,相信读者都有举一反三的能力,这里就不再讲解,需要的可下载demo查看源码


demo:http://download.csdn.net/detail/zhongwn/9531575

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值