在學習自定義Vew的時候,看到一篇文章,http://blog.csdn.net/nugongahou110/article/details/49159189,然後順着其思路寫了一下,實作效果如下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICdzFWRoRXdvN1LclHdpZXYyd2LcBzNvwVZ2x2bzNXak9CX90TQNNkRrFlQKBTSvwFbslmZvwFMwQzLcVmepNHdu9mZvwFVywUNMZTY18CX052bm9CX9UlMjlXOHFmZsh0Y3Z0RhZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DOzIjM1ATM4ETOwITM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
我們要做的事情:實作一個百分比的圓環進度條,包含三部分,分别是:
- 百分比文字
- 背景圓
- 動态圓環
我們要做的思路:
- 先分别繪制對應的圖形;
- 使圖形能動态變化;
- 文字顯示百分比與圓環進度對應;
會涉及到的基本知識點:
- 自定義View 會重寫三個方法;
- onMeasure()方法中,測量規則、測量大小、測量模式;
- TypedArray 擷取自定義屬性;
- canvas 繪制矩形内切圓;
自定義View PercentCircle.java:
public class PercentCircle extends View{
/**
* 繪制百分比的圓,一共有三部分,分别是裡面的文字、背景圓、圓環;
* 思路:首先需要三支畫筆, 設定畫筆對應的屬性等;
*/
private Paint mTextPaint;
private Paint mBackgroundPaint;
private Paint mRingPaint;
private int mCircleX;
private int mCircleY;
private float mCurrentAngle;
private RectF mArcRectF;
private float mStartSweepValue;
private float mTargetPercent;
private float mCurrentPercent;
private int mDefaultRadius = ;
private int mRadius;
private int mDefaultBackgroundColor = ;
private int mBackgroundColor;
private int mDefaultRingColor = ;
private int mRingColor;
private int mDefaultTextSize;
private int mTextSize;
private int mDefaultTextColor = ;
private int mTextColor;
public PercentCircle(Context context) {
super(context);
init(context);
}
public PercentCircle(Context context, AttributeSet attrs) {
super(context, attrs);
// 自定義屬性,attrs
// 使用TypedArray
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PercentCircle);
// 背景圓的半徑
mRadius = typedArray.getInt(R.styleable.PercentCircle_radius, mDefaultRadius);
// 背景圓的顔色
mBackgroundColor = typedArray.getColor(R.styleable.PercentCircle_background_color, mDefaultBackgroundColor);
// 文字的顔色 預設白色
mTextColor = typedArray.getColor(R.styleable.PercentCircle_text_color, mDefaultTextColor);
// 外圓環的顔色
mRingColor = typedArray.getColor(R.styleable.PercentCircle_ring_color, mDefaultRingColor);
// Be sure to call recycle() when done with them
typedArray.recycle();
init(context);
}
public PercentCircle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context){
//圓環開始角度 -90° 正北方向
mStartSweepValue = -;
//目前角度
mCurrentAngle = ;
//目前百分比
mCurrentPercent = ;
//設定中心園的畫筆
mBackgroundPaint = new Paint();
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setColor(mBackgroundColor);
mBackgroundPaint.setStyle(Paint.Style.FILL);
//設定文字的畫筆
mTextPaint = new Paint();
mTextPaint.setColor(mTextColor);
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setStrokeWidth((float) (*mRadius));
mTextPaint.setTextSize(mRadius/); //文字大小為半徑的一半
mTextPaint.setTextAlign(Paint.Align.CENTER);
//設定外圓環的畫筆
mRingPaint = new Paint();
mRingPaint.setAntiAlias(true);
mRingPaint.setColor(mRingColor);
mRingPaint.setStyle(Paint.Style.STROKE);
mRingPaint.setStrokeWidth((float) (*mRadius));
//獲得文字的字号 因為要設定文字在圓的中心位置
mTextSize = (int) mTextPaint.getTextSize();
}
// 主要是測量wrap_content時候的寬和高,因為寬高一樣,隻需要測量一次寬即可,高等于寬
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measure(widthMeasureSpec), measure(widthMeasureSpec));
}
// 當wrap_content的時候,view的大小根據半徑大小改變,但最大不會超過螢幕
private int measure(int measureSpec){
int result = ;
//1、先擷取測量模式 和 測量大小
//2、如果測量模式是MatchParent 或者精确值,則寬為測量的寬
//3、如果測量模式是WrapContent ,則寬為 直徑值 與 測量寬中的較小值;否則當直徑大于測量寬時,會繪制到螢幕之外;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if( specMode == MeasureSpec.EXACTLY){
result = specSize;
}else {
//result = 2*mRadius;
//result =(int) (1.075*mRadius*2);
result =(int) (mRadius* + mRingPaint.getStrokeWidth()*);
if(specMode == MeasureSpec.AT_MOST){
result = Math.min(result, specSize);
}
}
return result;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//1、如果半徑大于圓心的橫坐标,需要手動縮小半徑的值,否則畫到螢幕之外;
//2、改變了半徑,則需要重新設定字型大小;
//3、改變了半徑,則需要重新設定外圓環的寬度
//4、畫背景圓的外接矩形,用來畫圓環;
mCircleX = getMeasuredWidth()/;
mCircleY = getMeasuredHeight()/;
if(mRadius > mCircleX){
mRadius = mCircleX;
mRadius = (int) (mCircleX-*mRadius);
mTextPaint.setStrokeWidth((float) (*mRadius));
mTextPaint.setTextSize(mRadius/);
mRingPaint.setStrokeWidth((float) (*mRadius));
mTextSize = (int) mTextPaint.getTextSize();
}
mArcRectF = new RectF(mCircleX-mRadius, mCircleY-mRadius, mCircleX+mRadius, mCircleY+mRadius);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//1、畫中間背景圓
//2、畫文字
//3、畫圓環
//4、判斷進度,重新繪制
canvas.drawCircle(mCircleX, mCircleY, mRadius, mBackgroundPaint);
canvas.drawText(String.valueOf(mCurrentPercent)+"%", mCircleX, mCircleY+mTextSize/, mTextPaint);
canvas.drawArc(mArcRectF, mStartSweepValue, mCurrentAngle, false, mRingPaint);
if(mCurrentPercent < mTargetPercent){
//目前百分比+1
mCurrentPercent+=;
//目前角度+360
mCurrentAngle+=;
//每10ms重畫一次
postInvalidateDelayed();
}
//canvas.drawRect(mArcRectF, mRingPaint);
}
public void setTargetPercent(float targetPercent){
mTargetPercent = targetPercent;
}
}