轉載請注明出處:[http://blog.csdn.net/wingichoy/article/details/50334595](http://blog.csdn.net/wingichoy/article/details/50334595)
#### 起因
~~~
**注:本文由于是在學習過程中寫的,存在大量問題(overdraw onDraw new對象),請讀者們不要被誤導!!解決辦法見后面的博客。**
最近公司項目有需求需要用到輕量級圖表如下圖,是一些簡單的扇形圖,圓形圖,折線圖,雖然有好用的三方庫MPChart
(教程地址http://blog.csdn.net/wingichoy/article/details/50428246),
但是過于龐大,像這樣的簡約的界面明顯不合適,又因為許久沒有堅持寫博客,覺得自己很是墮落,深知自學不易,于是便想寫一些博客來幫助后來像我一樣的初學者,所以便想把這些效果寫一個系列。其中包括:
1.圓形百分比圖表
2.簡易折線圖圖表
3.簡易柱狀圖圖表
~~~

#### 效果圖
說了這么多沒有效果圖還是廢話,效果圖如下:

#### 預備知識
本篇博客的預備知識內容有:
1.自定義屬性
2.自定義view
關于以上兩點,可以查看 [Hongyang大神的博客:自定義View(一)](http://blog.csdn.net/lmj623565791/article/details/24252901 "Android 自定義View (一)")
#### 知識點補充
如果你已經掌握了以上的基本知識,那么可以開始本篇博客的內容啦。但是還是有幾點內容補充。
1.MeasureSpec對象包含了測量的模式和大小。他是一個32位的int值,其中高兩位為測量的模式,低30位是測量的大小。采用位運算和運行效率有關。所以可以從一個MeasureSpec對象分別獲取模式和值 如:
~~~
//獲取模式 值為 EXACTLY AT_MOST UNSPECIFIED
int specMode = MeasureSpec.getMode(measureSpec);
//獲取測量值
int specSize = MeasureSpec.getSize(measureSpec);
~~~
2.畫扇形,調用drawArc()方法,其中第一個參數是圓所在的矩形,第二個參數是開始的弧度,值得主意的是,最頂的弧度是270度,而地圖東方向的弧度為0.第三個參數是需要畫的弧度,第四個參數是一個布爾值,表示是否連接圓心,畫為扇形,第五個是Paint,即所需要的畫筆。
~~~
canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);
~~~
#### 現在開始吧
1.首先分析需求,我們的圓形進度總共分為三層,
最底層是一個大園形,作為底色。
第二層是一個扇形,大小跟底色一樣,用來表示進度。
第三層是一個小圓形,比背景色小,用于實現弧線的效果。
2.新建一個類叫做CirclePercentView.java 他繼承與View類重寫他的構造函數,來獲取他的自定義屬性。
~~~
public CirclePercentView(Context context) {
this(context, null);
}
public CirclePercentView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CirclePercentView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 獲取自定義屬性
TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.CirclePercentView, defStyleAttr, 0);
//獲取色帶的寬度
mStripeWidth = a.getDimension(R.styleable.CirclePercentView_stripeWidth, PxUtils.dpToPx(30, context));
//獲取當前的百分比
mCurPercent = a.getInteger(R.styleable.CirclePercentView_percent, 0);
//獲取小園的顏色
mSmallColor = a.getColor(R.styleable.CirclePercentView_smallColor,0xffafb4db);
//獲取大圓的顏色
mBigColor = a.getColor(R.styleable.CirclePercentView_bigColor,0xff6950a1);
//獲取中心文字的大小
mCenterTextSize = a.getDimensionPixelSize(R.styleable.CirclePercentView_centerTextSize,PxUtils.spToPx(20,context));
//獲取園的半徑
mRadius = a.getDimensionPixelSize(R.styleable.CirclePercentView_radius,PxUtils.dpToPx(100,context));
}
~~~
3.獲取到了自定義屬性以后,我們來測量這個view,告訴系統這個view有多大
~~~
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//獲取測量模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//獲取測量大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//如果為確定大小值,則圓的半徑為寬度/2
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
mRadius = widthSize / 2;
x = widthSize / 2;
y = heightSize / 2;
mWidth = widthSize;
mHeight = heightSize;
}
//如果為wrap_content 那么View大小為圓的半徑大小*2
if(widthMode == MeasureSpec.AT_MOST&&heightMode ==MeasureSpec.AT_MOST){
mWidth = (int) (mRadius*2);
mHeight = (int) (mRadius*2);
x = mRadius;
y = mRadius;
}
//設置視圖的大小
setMeasuredDimension(mWidth,mHeight);
}
~~~
4.測量完成后,我們就要開始畫view了。首先畫大圓,之后畫扇形圖,最后畫小圓蓋住
就有了圓形進度條的效果,之后把百分比進度文字畫在上面就大功告成啦。
具體步驟如圖:


~~~
@Override
protected void onDraw(Canvas canvas) {
mEndAngle = (int) (mCurPercent * 3.6);
//繪制大圓
Paint bigCirclePaint = new Paint();
//消除鋸齒
bigCirclePaint.setAntiAlias(true);
bigCirclePaint.setColor(mBigColor);
//x,y 為圓心坐標 mRadius為半徑
canvas.drawCircle(x, y, mRadius, bigCirclePaint);
//餅狀圖
Paint sectorPaint = new Paint();
sectorPaint.setColor(mSmallColor);
sectorPaint.setAntiAlias(true);
RectF rect = new RectF(0, 0, mWidth, mHeight);
//參數說明見知識補充
canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);
//繪制小圓
Paint smallCirclePaint = new Paint();
smallCirclePaint.setAntiAlias(true);
smallCirclePaint.setColor(mBigColor);
//圓心是相同的 不過半徑有差別,這個差別就是我們的 色帶寬度
canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint);
//繪制文本
Paint textPaint = new Paint();
String text = mCurPercent + "%";
textPaint.setTextSize(mCenterTextSize);
//測量字符串長度
float textLength = textPaint.measureText(text);
textPaint.setColor(Color.WHITE);
//把文本畫在圓心居中
canvas.drawText(text, x - textLength/2, y, textPaint);
}
~~~
值得注意的是,在編寫的過程中,文字的位置總是不對,但是根據畫圖計算,
公式是沒錯的,最后才發現我先測量了字符串長度,又修改了字體的大小導致偏差。所以一定要注意這些細節,先改變字體大小,再去測量。
5.添加setPercent方法
~~~
public void setPercent(int percent) {
//百分比不可能超過100 如果超過100則拋出異常
if (percent > 100) {
throw new IllegalArgumentException("percent must less than 100!");
}
setCurPercent(percent);
}
//內部設置百分比 用于動畫效果
private void setCurPercent(int percent) {
mPercent = percent;
new Thread(new Runnable() {
@Override
public void run() {
for(int i =0;i<mPercent;i++){
try {
Thread.sleep(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
mCurPercent = i;
CirclePercentView.this.postInvalidate();
}
}
}).start();
}
~~~
這里在setPercent改變的時候,開啟一個線程,來不斷重繪view,達到一個動畫效果。其實view的動畫效果就是不停地重繪
(即執行onDraw(),因為每次執行onDraw()里面的參數會變化,所以會看到不同的畫面)。這樣便完成了一個輕量級的圓形百分比進度條自定義View。
你可以在[https://github.com/githubwing/CirclePercentView](https://github.com/githubwing/CirclePercentView)克隆到源碼。(求star)
你還可以看本系列第二篇博客:簡易折線圖,鏈接:[http://blog.csdn.net/wingichoy/article/details/50434634](http://blog.csdn.net/wingichoy/article/details/50434634)。
- 前言
- android自定義viewgroup初步之一----抽屜菜單
- Android 自定義view --圓形百分比(進度條)
- Android 自定義View -- 簡約的折線圖
- 新手自定義view練習實例之(一) 泡泡彈窗
- 新手自定義view練習實例之(二) 波浪view
- 手把手帶你畫一個 時尚儀表盤 Android 自定義View
- 手把手帶你畫一個動態錯誤提示 Android自定義view
- 手把手帶你做一個超炫酷loading成功動畫view Android自定義view
- 關于Android自定義view 你所需要知道的基本函數
- Android自定義view進階-- 神奇的貝塞爾曲線
- wing帶你玩轉自定義view系列(1) 仿360內存清理效果
- wing帶你玩轉自定義view系列(2) 簡單模仿qq未讀消息去除效果
- wing帶你玩轉自定義view系列(3)模仿微信下拉眼睛
- 手把手教你畫一個 逼格滿滿圓形水波紋loadingview Android
- 有坑?? 為何wing墜入PorterDuffXferMode的萬丈深淵(PorterDuffXferMode深入試驗)
- 手把手帶你畫一個漂亮蜂窩view Android自定義view
- 一個炫字都不夠??!!!手把手帶你打造3D自定義view
- 恭喜發財! -- 手把手教你仿造一個qq下拉搶紅包 Android自定義view