帶進度的圓形進度條的實現
阿新 • • 發佈:2019-02-17
今天通過自定義View來實現一個帶進度的圓形進度條,實現的最終效果如下圖所示:
現在來講一下設計的思路:首先這個進度條可以自定義小圓角矩形的數量、小圓角矩形大小、小圓角矩形的圓角角度、未完成進度時的顏色,完成進度時的顏色、文字大小、文字顏色、圓形半徑,所以需要自定義這些引數;那如何畫這個圓形進度呢?我們需要先畫一個小圓角矩形,再旋轉畫布再畫矩形,如圖這裡有12個小圓角矩形,每次旋轉360/12=30度,畫一個小圓角矩形,共畫12個。然後畫中間的進度值,畫中間的進度值,主要需要計算文字的位置,這個稍後再介紹。下面通過程式碼進行詳細的講解下實現過程。程式碼如下:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.support.annotation.FloatRange;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
* Created by 劉信 on 2018/4/27.
*/
public class LoadView extends View {
//已經load的顏色值
private int mHasLoadColor;
//沒有load的顏色值
private int mNormalLoadColor;
//小長方形的寬度
private int mRectangleWidth;
//小長方形的高度
private int mRectangleHeight;
//小長方形的個數
private int mRectangleNum;
//小長方形圓角度
private int mRectangleRadius;
//內半徑大小
//內半徑指不包括方塊的大小
private int mInnerRadius;
//外半徑
private int mOuterRadius;
//文字大小
private int mTextSize;
//畫筆
private Paint mPaint;
//文字的畫筆
private TextPaint mTextPaint;
//小長方形
private RectF mRectF;
private Context mContext;
//百分比字串
private String mPercentStr;
//百分比
private float mPercent;
public LoadView(Context context) {
this(context, null);
}
public LoadView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LoadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int deStyleAttr) {
mContext = context;
TypedArray typedArray = mContext.obtainStyledAttributes(attrs, R.styleable.LoadView, deStyleAttr, 0);
//下面是一些自定義引數的預設值
mHasLoadColor = mContext.getResources().getColor(R.color.color_3398ab);
mNormalLoadColor = mContext.getResources().getColor(R.color.color_e0e0e0);
mRectangleWidth = dipToPixels(mContext, 14);
mRectangleHeight = dipToPixels(mContext, 28);
mRectangleNum = 12;
mInnerRadius = dipToPixels(mContext, 85);
mTextSize = dipToPixels(mContext, 48);
mRectangleRadius = dipToPixels(mContext, 3);
mPercentStr = "0%";
mPercent = 0f;
if (typedArray != null) {
//從xml中讀取這些引數設定
mHasLoadColor = typedArray.getColor(R.styleable.LoadView_HasLoadColor, mHasLoadColor);
mNormalLoadColor = typedArray.getColor(R.styleable.LoadView_NormalLoadColor, mNormalLoadColor);
mRectangleWidth = typedArray.getDimensionPixelSize(R.styleable.LoadView_RectangleWidth, mRectangleWidth);
mRectangleHeight = typedArray.getDimensionPixelSize(R.styleable.LoadView_RectangleHeight, mRectangleHeight);
mRectangleNum = typedArray.getInteger(R.styleable.LoadView_RectangleNum, mRectangleNum);
mInnerRadius = typedArray.getDimensionPixelSize(R.styleable.LoadView_InnerRadius, mInnerRadius);
mTextSize = typedArray.getDimensionPixelSize(R.styleable.LoadView_TextSize, mTextSize);
mRectangleRadius = typedArray.getDimensionPixelSize(R.styleable.LoadView_RectangleRadius, mRectangleRadius);
typedArray.recycle();
}
//外半徑等於使用者設定的內半徑加上小矩形的高度
mOuterRadius = mInnerRadius + mRectangleHeight;
//這裡是畫第一個圓形矩形需要的RetcF。通過左上角和右下角座標確定,
// 這裡左上角座標(mOuterRadius - mRectangleWidth / 2f,0),
//右下角座標(mOuterRadius + mRectangleWidth / 2f, mRectangleHeight);
mRectF = new RectF(mOuterRadius - mRectangleWidth / 2f, 0, mOuterRadius + mRectangleWidth / 2f, mRectangleHeight);
mPaint = new Paint();
mPaint.setColor(mNormalLoadColor);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.FILL);
mTextPaint = new TextPaint();
//這裡還可以設定文字的字型,我去掉了
/*try {
Typeface typeface = Typeface.createFromFile("fonts/MyriadPro-Bold.otf");
mTextPaint.setTypeface(typeface);
} catch (Exception e) {
e.printStackTrace();
}*/
mTextPaint.setTextSize(mTextSize);
mTextPaint.setColor(mHasLoadColor);
}
private int dipToPixels(Context context, float dip) {
final float SCALE = context.getResources().getDisplayMetrics().density;
float valueDips = dip;
int valuePixels = (int)(valueDips * SCALE + 0.5f);
return valuePixels;
}
/**
*供外界呼叫
* 請在主執行緒呼叫,設定進度 0到1
* @param percent
*/
public void setPercent(@FloatRange(from=0.0, to=1.0) float percent){
this.mPercent=percent;
this.mPercentStr=Math.round(percent*100)+"%";
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//強制寬高度,在xml檔案中設定寬高無效
//設定大小請根據半徑、小長方形大小來設定
int defaultSize = 2 * (mInnerRadius + mRectangleHeight);
setMeasuredDimension(defaultSize, defaultSize);
}
@Override
protected void onDraw(Canvas canvas) {
int hasDownCount = 0;//已經下載百分比換算成需要畫多少個已經load的長方形
hasDownCount = Math.round(mPercent * mRectangleNum);//才用四捨五入
//旋轉之前先儲存下畫布的狀態
canvas.save();
//每次旋轉需要的角度
float degress = 360.0f / mRectangleNum;
for (int i = 0; i < mRectangleNum; i++) {
if (hasDownCount > i) {
//已經load的顏色
mPaint.setColor(mHasLoadColor);
} else {
//沒有load的顏色
mPaint.setColor(mNormalLoadColor);
}
//畫圓角矩形
canvas.drawRoundRect(mRectF, mRectangleRadius, mRectangleRadius, mPaint);
//以中心點旋轉畫布,這裡想象下你現實中拿只筆在紙上畫,每畫一個你就旋轉紙,你就知道了
canvas.rotate(degress, mOuterRadius, mOuterRadius);
}
//回到之前的畫布狀態
canvas.restore();
//文字寬度
float textWidth = mTextPaint.measureText(mPercentStr);
//計算高度要注意了
//drawText是以文字的BaseLine為準的
//所以計算高度步驟:文字高度(descent-ascent)的一半減去descent;得到的結果
// 是Baseline離中心圓點的偏移量,再加上半徑就是高度了
//還不懂?看下面的圖
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
float diffBaseLine = (-(fontMetrics.ascent + fontMetrics.descent)) / 2;
//x預設是這個字串的左邊在螢幕的位置,如果設定了paint.setTextAlign(Paint.Align.CENTER);那就是字元的中心,y是指定這個字元baseline在螢幕上的位置
canvas.drawText(mPercentStr, mOuterRadius - textWidth / 2, mOuterRadius + diffBaseLine, mTextPaint);
}
}