自定義圓角進度條以及顏色漸變的進度條
先上圖,給個直觀印象
一、先來看看漸變的圓角
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查看源碼