1.首先看效果圖 2.自定義PieChartView,繼承自View,下邊為PieChartView代碼 之後,在activity中,只需找到組件,傳入數據,調用 invalidate() 進行重繪即可。 ...
1.首先看效果圖
2.自定義PieChartView,繼承自View,下邊為PieChartView代碼
package com.yingjinbao.im.peach.customview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by wanger on 07/19/2018.
*/
public class PieChartView extends View {
private int mHeight, mWidth;//寬高
private Paint mPaint;//扇形的畫筆
private Paint mTextPaint;//畫文字的畫筆
private int centerX, centerY;//中心坐標
private int maxNum = 4;//扇形圖的最大塊數,超出部分自動合併到最後一塊上去
double total;//數據的總和
double[] datas;//數據集
String[] texts;//每個數據對應的文字集
//顏色 預設的顏色
private int[] mColors = {
Color.parseColor("#FFC65B"), Color.parseColor("#FD5998"),
Color.parseColor("#8971FB"), Color.parseColor("#676974")
};
private int mTextSize;//文字大小
private int radius = 1000;//半徑
public PieChartView(Context context) {
super(context);
}
public PieChartView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//初始化
private void init() {
mTextSize = 25;
mPaint = new Paint();
//當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的圖形樣式, 如圓形樣Cap.ROUND,或方形樣式Cap.SQUARE
mPaint.setStrokeCap(Paint.Cap.ROUND);
//設置是否使用抗鋸齒功能,會消耗較大資源,繪製圖形速度會變慢。
mPaint.setAntiAlias(true);
mTextPaint = new Paint();
//設置繪製文字的字型大小大小
mTextPaint.setTextSize(mTextSize);
//當畫筆樣式為STROKE或FILL_OR_STROKE時,設置筆刷的粗細度
mTextPaint.setStrokeWidth(3);
//設置是否使用抗鋸齒功能,會消耗較大資源,繪製圖形速度會變慢。
mTextPaint.setAntiAlias(true);
//設置繪製的顏色,使用顏色值來表示,該顏色值包括透明度和RGB顏色。
mTextPaint.setColor(Color.WHITE);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲取寬高 不要設置wrap_content
mHeight = MeasureSpec.getSize(heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//無數據
if (datas == null || datas.length == 0) return;
centerX = (getRight() - getLeft()) / 2;
centerY = (getBottom() - getTop()) / 2;
int min = mHeight > mWidth ? mWidth : mHeight;
if (radius > min / 2) {
radius = (int) ((min - getPaddingTop() - getPaddingBottom()) / 3.5);
}
//畫扇形
canvas.save();
drawCircle(canvas);
canvas.restore();
//線與文字
canvas.save();
drawLineAndText(canvas);
canvas.restore();
}
//畫線與文字
private void drawLineAndText(Canvas canvas) {
int start = 0;
canvas.translate(centerX, centerY);//平移畫布到中心
mPaint.setStrokeWidth(4);
for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) {
if (i == (maxNum < datas.length ? maxNum : datas.length) - 1){
drawLine(canvas, start, 360 - start, texts[i], mColors[i % mColors.length],i);
}else {
float angles = (float) ((datas[i] * 1.0f / total) * 360);
drawLine(canvas, start, angles, texts[i], mColors[i % mColors.length],i);
start += angles;
}
}
}
private void drawLine(Canvas canvas, int start, float angles, String text, int color,int position) {
mPaint.setColor(color);
//mTextPaint.setColor(color);
float stopX, stopY;
stopX = (float) ((radius + 40) * Math.cos((2 * start + angles) / 2 * Math.PI / 180));
stopY = (float) ((radius + 40) * Math.sin((2 * start + angles) / 2 * Math.PI / 180));
switch (position){
case 0:
canvas.drawLine((float) ((radius * 0.5) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.5) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 1:
canvas.drawLine((float) ((radius * 0.7) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.7) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 2:
canvas.drawLine((float) ((radius * 1.1) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 1.1) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
case 3:
canvas.drawLine((float) ((radius * 0.9) * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) ((radius * 0.9) * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
default:
canvas.drawLine((float) (radius * Math.cos((2 * start + angles) / 2 * Math.PI / 180)),
(float) (radius * Math.sin((2 * start + angles) / 2 * Math.PI / 180)),
stopX, stopY, mPaint);
break;
}
//canvas.drawLine(0, 0, stopX, stopY, mPaint);
//畫橫線
int dx;//判斷橫線是畫在左邊還是右邊
int endX;
if (stopX > 0) {
endX = (int) (stopX + 110);
} else {
endX = (int) (stopX - 110);
}
//畫橫線
canvas.drawLine(stopX, stopY,
endX, stopY, mPaint
);
dx = (int) (endX - stopX);
//測量文字大小
Rect rect = new Rect();
mTextPaint.getTextBounds(text, 0, text.length(), rect);
int w = rect.width();
int h = rect.height();
int offset = 20;//文字在橫線的偏移量
//畫文字
canvas.drawText(text, 0, text.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY - 5, mTextPaint);
//測量百分比大小
String percentage = (datas[position] / total) * 100 + "";
percentage = percentage.substring(0, percentage.length() > 4 ? 4 : percentage.length()) + "%";
mTextPaint.getTextBounds(percentage, 0, percentage.length(), rect);
w = rect.width() - 10;
//畫百分比
canvas.drawText(percentage, 0, percentage.length(), dx > 0 ? stopX + offset : stopX - w - offset, stopY + h, mTextPaint);
}
//畫扇形
private void drawCircle(Canvas canvas) {
RectF rect = null;
int start = 0;
for (int i = 0; i < (maxNum < datas.length ? maxNum : datas.length); i++) {
if (i == 0){
rect = new RectF((float) (centerX - radius * 0.5), (float) (centerY - radius * 0.5),
(float) (centerX + radius * 0.5), (float) (centerY + radius * 0.5));
}else if (i == 1){
rect = new RectF((float) (centerX - radius * 0.7), (float) (centerY - radius * 0.7),
(float) (centerX + radius * 0.7), (float) (centerY + radius * 0.7));
}else if (i == 2){
rect = new RectF((float) (centerX - radius * 1.1), (float) (centerY - radius * 1.1),
(float) (centerX + radius * 1.1), (float) (centerY + radius * 1.1));
}else if (i == 3){
rect = new RectF((float) (centerX - radius * 0.9), (float) (centerY - radius * 0.9),
(float) (centerX + radius * 0.9), (float) (centerY + radius * 0.9));
}else {
rect = new RectF((float) (centerX - radius * 1), (float) (centerY - radius * 1),
(float) (centerX + radius * 1), (float) (centerY + radius * 1));
}
if (i == (maxNum < datas.length ? maxNum : datas.length) - 1){
float angles = 360 - start;
mPaint.setColor(mColors[i % mColors.length]);
if (i == 2){
canvas.drawArc(rect, start, angles, true, mPaint);
mPaint.setColor(Color.parseColor("#34374A"));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(8);
rect = new RectF((float) (centerX - radius * 1.03), (float) (centerY - radius * 1.03),
(float) (centerX + radius * 1.03), (float) (centerY + radius * 1.03));
canvas.drawArc(rect, start, angles, false, mPaint);
init();
}else {
canvas.drawArc(rect, start, angles, true, mPaint);
}
start += angles;
}else {
float angles = (float) ((datas[i] * 1.0f / total) * 360);
mPaint.setColor(mColors[i % mColors.length]);
if (i == 2){
canvas.drawArc(rect, start, angles, true, mPaint);
mPaint.setColor(Color.parseColor("#34374A"));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(8);
rect = new RectF((float) (centerX - radius * 1.03), (float) (centerY - radius * 1.03),
(float) (centerX + radius * 1.03), (float) (centerY + radius * 1.03));
canvas.drawArc(rect, start, angles, false, mPaint);
init();
}else {
canvas.drawArc(rect, start, angles, true, mPaint);
}
start += angles;
}
}
}
//setter
public void setColors(int[] mColors) {
this.mColors = mColors;
invalidate();
}
public void setTextSize(int mTextSize) {
this.mTextSize = mTextSize;
mTextPaint.setTextSize(mTextSize);
invalidate();
}
public void setRadius(int radius) {
this.radius = radius;
invalidate();
}
public void setMaxNum(int maxNum) {
this.maxNum = maxNum;
invalidate();
}
public void setDatas(double[] datas) {
this.datas = datas;
total = 0;
for (int i = 0;i < datas.length;i++){
total += datas[i];
}
}
public void setTexts(String[] texts) {
this.texts = texts;
}
}
3.使用,首先在XML文件中調用
之後,在activity中,只需找到組件,傳入數據,調用 invalidate() 進行重繪即可。