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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章