Android編程實(shí)現(xiàn)canvas繪制餅狀統(tǒng)計(jì)圖功能示例【自動(dòng)適應(yīng)條目數(shù)量與大小】
本文實(shí)例講述了Android編程實(shí)現(xiàn)canvas繪制餅狀統(tǒng)計(jì)圖功能。分享給大家供大家參考,具體如下:
本例的目的是實(shí)現(xiàn)一個(gè)簡(jiǎn)單的餅狀統(tǒng)計(jì)圖,效果如下:

特點(diǎn):
1.使用非常方便,可放在xml布局文件中,然后在代碼中設(shè)置內(nèi)容,即:
PieChartView pieChartView = (PieChartView) findViewById(R.id.pie_chart);
PieChartView.PieItemBean[] items = new PieChartView.PieItemBean[]{
new PieChartView.PieItemBean("娛樂(lè)", 200),
new PieChartView.PieItemBean("旅行", 100),
new PieChartView.PieItemBean("學(xué)習(xí)", 120),
new PieChartView.PieItemBean("人際關(guān)系", 160),
new PieChartView.PieItemBean("交通", 100),
new PieChartView.PieItemBean("餐飲", 480)
};
pieChartView.setPieItems(items);
2.條目數(shù)量,大小及折線位置,長(zhǎng)度均自適應(yīng)。左側(cè)條目往左側(cè)劃線,右側(cè)條目往右側(cè)劃線,文字描述與百分比居中對(duì)齊,并且文字“下劃線”與文字長(zhǎng)度自適應(yīng)。對(duì)于很小的條目,將自動(dòng)將折線延長(zhǎng)以盡可能避免文字遮蓋
核心代碼:PieChartView.Java:
public class PieChartView extends View {
private int screenW, screenH;
/**
* The paint to draw text, pie and line.
*/
private Paint textPaint, piePaint, linePaint;
/**
* The center and the radius of the pie.
*/
private int pieCenterX, pieCenterY, pieRadius;
/**
* The oval to draw the oval in.
*/
private RectF pieOval;
private float smallMargin;
private int[] mPieColors = new int[]{Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.MAGENTA, Color.CYAN};
private PieItemBean[] mPieItems;
private float totalValue;
public PieChartView(Context context) {
super(context);
init(context);
}
public PieChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public PieChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
//init screen
screenW = ScreenUtils.getScreenW(context);
screenH = ScreenUtils.getScreenH(context);
pieCenterX = screenW / 2;
pieCenterY = screenH / 3;
pieRadius = screenW / 4;
smallMargin = ScreenUtils.dp2px(context, 5);
pieOval = new RectF();
pieOval.left = pieCenterX - pieRadius;
pieOval.top = pieCenterY - pieRadius;
pieOval.right = pieCenterX + pieRadius;
pieOval.bottom = pieCenterY + pieRadius;
//The paint to draw text.
textPaint = new Paint();
textPaint.setAntiAlias(true);
textPaint.setTextSize(ScreenUtils.dp2px(context, 16));
//The paint to draw circle.
piePaint = new Paint();
piePaint.setAntiAlias(true);
piePaint.setStyle(Paint.Style.FILL);
//The paint to draw line to show the concrete text
linePaint = new Paint();
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(ScreenUtils.dp2px(context, 1));
}
//The degree position of the last item arc's center.
private float lastDegree = 0;
//The count of the continues 'small' item.
private int addTimes = 0;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mPieItems != null && mPieItems.length > 0) {
float start = 0.0f;
for (int i = 0; i < mPieItems.length; i++) {
//draw pie
piePaint.setColor(mPieColors[i % mPieColors.length]);
float sweep = mPieItems[i].getItemValue() / totalValue * 360;
canvas.drawArc(pieOval, start, sweep, true, piePaint);
//draw line away from the pie
float radians = (float) ((start + sweep / 2) / 180 * Math.PI);
float lineStartX = pieCenterX + pieRadius * 0.7f * (float) (Math.cos(radians));
float lineStartY = pieCenterY + pieRadius * 0.7f * (float) (Math.sin(radians));
float lineStopX, lineStopY;
float rate;
if (getOffset(start + sweep / 2) > 60) {
rate = 1.3f;
} else if (getOffset(start + sweep / 2) > 30) {
rate = 1.2f;
} else {
rate = 1.1f;
}
//If the item is very small, make the text further away from the pie to avoid being hided by other text.
if (start + sweep / 2 - lastDegree < 30) {
addTimes++;
rate += 0.2f * addTimes;
} else {
addTimes = 0;
}
lineStopX = pieCenterX + pieRadius * rate * (float) (Math.cos(radians));
lineStopY = pieCenterY + pieRadius * rate * (float) (Math.sin(radians));
canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, linePaint);
//write text
String itemTypeText = mPieItems[i].getItemType();
String itemPercentText = Utility.formatFloat(mPieItems[i].getItemValue() / totalValue * 100) + "%";
float itemTypeTextLen = textPaint.measureText(itemTypeText);
float itemPercentTextLen = textPaint.measureText(itemPercentText);
float lineTextWidth = Math.max(itemTypeTextLen, itemPercentTextLen);
float textStartX = lineStopX;
float textStartY = lineStopY - smallMargin;
float percentStartX = lineStopX;
float percentStartY = lineStopY + textPaint.getTextSize();
if (lineStartX > pieCenterX) {
textStartX += (smallMargin + Math.abs(itemTypeTextLen - lineTextWidth) / 2);
percentStartX += (smallMargin + Math.abs(itemPercentTextLen - lineTextWidth) / 2);
} else {
textStartX -= (smallMargin + lineTextWidth - Math.abs(itemTypeTextLen - lineTextWidth) / 2);
percentStartX -= (smallMargin + lineTextWidth - Math.abs(itemPercentTextLen - lineTextWidth) / 2);
}
canvas.drawText(itemTypeText, textStartX, textStartY, textPaint);
//draw percent text
canvas.drawText(itemPercentText, percentStartX, percentStartY, textPaint);
//draw text underline
float textLineStopX = lineStopX;
if (lineStartX > pieCenterX) {
textLineStopX += (lineTextWidth + smallMargin * 2);
} else {
textLineStopX -= (lineTextWidth + smallMargin * 2);
}
canvas.drawLine(lineStopX, lineStopY, textLineStopX, lineStopY, linePaint);
lastDegree = start + sweep / 2;
start += sweep;
}
}
}
public PieItemBean[] getPieItems() {
return mPieItems;
}
public void setPieItems(PieItemBean[] pieItems) {
this.mPieItems = pieItems;
totalValue = 0;
for (PieItemBean item : mPieItems) {
totalValue += item.getItemValue();
}
invalidate();
}
private float getOffset(float radius) {
int a = (int) (radius % 360 / 90);
switch (a) {
case 0:
return radius;
case 1:
return 180 - radius;
case 2:
return radius - 180;
case 3:
return 360 - radius;
}
return radius;
}
static class PieItemBean {
private String itemType;
private float itemValue;
PieItemBean(String itemType, float itemValue) {
this.itemType = itemType;
this.itemValue = itemValue;
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public float getItemValue() {
return itemValue;
}
public void setItemValue(float itemValue) {
this.itemValue = itemValue;
}
}
}
完整實(shí)例代碼點(diǎn)擊此處本站下載。
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Android圖形與圖像處理技巧總結(jié)》、《Android開(kāi)發(fā)入門與進(jìn)階教程》、《Android調(diào)試技巧與常見(jiàn)問(wèn)題解決方法匯總》、《Android基本組件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android布局layout技巧總結(jié)》及《Android控件用法總結(jié)》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
- Android中使用Canvas繪制南丁格爾玫瑰圖(Nightingale rose diagram)
- Android編程之canvas繪制各種圖形(點(diǎn),直線,弧,圓,橢圓,文字,矩形,多邊形,曲線,圓角矩形)
- Android編程開(kāi)發(fā)之在Canvas中利用Path繪制基本圖形(圓形,矩形,橢圓,三角形等)
- Android使用Canvas繪制圓形進(jìn)度條效果
- Android編程實(shí)現(xiàn)canvas繪制柱狀統(tǒng)計(jì)圖功能【自動(dòng)計(jì)算寬高及分度值、可左右滑動(dòng)】
- Android開(kāi)發(fā)使用自定義View將圓角矩形繪制在Canvas上的方法
- Android 使用Canvas在圖片上繪制文字的方法
- Android Canvas繪制文字橫縱向?qū)R
相關(guān)文章
Android中對(duì)xml文件解析的3種方式總結(jié)
這篇文章主要給大家介紹了關(guān)于Android中對(duì)xml文件解析的3種方式,分別是 Dom 、 SAX 和 dom4j,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-02-02
AndroidHttpClient詳解及調(diào)用示例
本文給大家介紹AndroidHttpClient結(jié)構(gòu)、使用方式及調(diào)用示例詳解,需要的朋友可以參考下2015-10-10
詳解Android Studio正式簽名進(jìn)行調(diào)試的實(shí)現(xiàn)步驟
這篇文章主要介紹了詳解Android Studio正式簽名進(jìn)行調(diào)試的實(shí)現(xiàn)步驟的相關(guān)資料,需要的朋友可以參考下2017-07-07
Android音樂(lè)播放器簡(jiǎn)單實(shí)現(xiàn)案例
我們平時(shí)長(zhǎng)時(shí)間打代碼的時(shí)候肯定會(huì)感到疲憊和乏味,這個(gè)時(shí)候一邊播放自己喜歡的音樂(lè),一邊繼續(xù)打代碼,心情自然也愉快很多。音樂(lè)帶給人的聽(tīng)覺(jué)享受是無(wú)可比擬的,動(dòng)聽(tīng)的音樂(lè)可以愉悅?cè)说纳硇模屓烁臃e極地去熱愛(ài)生活,這篇文章主要介紹了Android音樂(lè)播放器簡(jiǎn)單實(shí)現(xiàn)案例2022-12-12
Eclipse NDK遷移到Android Studio的方法示例
本篇文章主要介紹了Eclipse NDK遷移到Android Studio的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
Android組件banner實(shí)現(xiàn)左右滑屏效果
這篇文章主要為大家詳細(xì)介紹了Android組件banner實(shí)現(xiàn)左右滑屏效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
淺析KJFrameForAndroid框架如何高效加載Bitmap
Bitmap是Android系統(tǒng)中的圖像處理的最重要類之一。用它可以獲取圖像文件信息,進(jìn)行圖像剪切、旋轉(zhuǎn)、縮放等操作,并可以指定格式保存圖像文件。本文主要是從KJFrameForAndroid框架中分析高效加載Bitmap的方法2014-07-07
詳解Android跨進(jìn)程IPC通信AIDL機(jī)制原理
本篇文章主要介紹了詳解Android跨進(jìn)程IPC通信AIDL機(jī)制原理,詳細(xì)的介紹了AIDL的概念和使用,具有一定的參考價(jià)值,有興趣的可以了解一下2018-01-01
Android 判斷程序在前臺(tái)運(yùn)行還是后臺(tái)運(yùn)行
本文主要介紹了Android 判斷程序在前臺(tái)運(yùn)行還是后臺(tái)運(yùn)行的方法。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04

