package com.signin;
import android.content.Context;
import android.content.res.TypedArray;
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;
import java.util.Random;
/**
* Created by xxxx on 2018/8/29.
*/
public class SignChartView extends View {
/**
* 使用wrap_content時默認的尺寸
*/
private static final int DEFAULT_WIDTH = 220;
private static final int DEFAULT_HEIGHT = 220;
/**
* 中心座標
*/
private int centerX;
private int centerY;
/**
* 半徑
*/
private float radius;
/**
* 弧形外接矩形
*/
private RectF rectF;
/**
* 中間文本的大小
*/
private Rect centerTextBound = new Rect();
/**
* 數據文本的大小
*/
private Rect dataTextBound = new Rect();
/**
* 扇形畫筆
*/
private Paint mArcPaint;
/**
* 中心文本畫筆
*/
private Paint centerTextPaint;
/**
* 數據畫筆
*/
private Paint dataPaint;
/**
* 數據源數字數組
*/
private int[] numbers;
/**
* 數據源名稱數組
*/
private String[] names;
/**
* 數據源總和
*/
private int sum;
/**
* 顏色數組
*/
private int[] colors;
private Random random = new Random();
//自定義屬性 Start
/**
* 中間字體大小
*/
private float centerTextSize = 80;
/**
* 數據字體大小
*/
private float dataTextSize = 30;
/**
* 中間字體顏色
*/
private int centerTextColor = Color.BLACK;
/**
* 數據字體顏色
*/
private int dataTextColor = Color.BLACK;
/**
* 圓圈的寬度
*/
private float circleWidth = 100;
//自定義屬性 End
public SignChartView(Context context) {
super(context);
init();
}
public SignChartView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SignChartView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PieView);
centerTextSize = typedArray.getDimension(R.styleable.PieView_centerTextSize, centerTextSize);
dataTextSize = typedArray.getDimension(R.styleable.PieView_dataTextSize, dataTextSize);
circleWidth = typedArray.getDimension(R.styleable.PieView_circleWidth, circleWidth);
centerTextColor = typedArray.getColor(R.styleable.PieView_centerTextColor, centerTextColor);
dataTextColor = typedArray.getColor(R.styleable.PieView_dataTextColor, dataTextColor);
typedArray.recycle();
init();
}
/**
* 初始化
*/
private void init() {
mArcPaint = new Paint();
mArcPaint.setStrokeWidth(circleWidth);
mArcPaint.setAntiAlias(true);
mArcPaint.setStyle(Paint.Style.STROKE);
centerTextPaint = new Paint();
centerTextPaint.setTextSize(centerTextSize);
centerTextPaint.setAntiAlias(true);
centerTextPaint.setTextAlign(Paint.Align.CENTER);
centerTextPaint.setColor(centerTextColor);
dataPaint = new Paint();
dataPaint.setStrokeWidth(2);
dataPaint.setTextSize(dataTextSize);
dataPaint.setAntiAlias(true);
dataPaint.setColor(dataTextColor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int measureWidthSize = MeasureSpec.getSize(widthMeasureSpec);
int measureHeightSize = MeasureSpec.getSize(heightMeasureSpec);
int measureWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int measureHeightMode = MeasureSpec.getMode(heightMeasureSpec);
if (measureWidthMode == MeasureSpec.AT_MOST
&& measureHeightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(DEFAULT_WIDTH, DEFAULT_HEIGHT);
} else if (measureWidthMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(DEFAULT_WIDTH, measureHeightSize);
} else if (measureHeightMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(measureWidthSize, DEFAULT_HEIGHT);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerX = getMeasuredWidth() / 2;
centerY = getMeasuredHeight() / 2;
//設置半徑爲寬高最小值的1/4
radius = Math.min(getMeasuredWidth(), getMeasuredHeight()) / 4;
//設置扇形外接矩形
rectF = new RectF(centerX - radius,
centerY - radius,
centerX + radius,
centerY + radius);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
calculateAndDraw(canvas);
}
/**
* 計算比例而且繪製扇形和數據
*/
private void calculateAndDraw(Canvas canvas) {
if (numbers == null || numbers.length == 0) {
return;
}
//扇形開始度數
int startAngle = 0;
//所佔百分比
float percent;
//所佔度數
float angle;
for (int i = 0; i < numbers.length; i++) {
percent = numbers[i] / (float) sum;
//獲取百分比在360中所佔度數
if (i == numbers.length - 1) {//保證全部度數加起來等於360
angle = 360 - startAngle;
} else {
angle = (float) Math.ceil(percent * 360);
}
//繪製第i段扇形
drawArc(canvas, startAngle, angle, colors[i]);
startAngle += angle;
//繪製數據
if (numbers[i] <= 0) {
continue;
}
//當前弧線中心點相對於縱軸的夾角度數,因爲扇形的繪製是從三點鐘方向開始,因此加90
float arcCenterDegree = 90 + startAngle - angle / 2;
drawData(canvas, arcCenterDegree, i, percent);
}
//繪製中心數字總和
canvas.drawText(sum + "", centerX, centerY + centerTextBound.height() / 2, centerTextPaint);
}
/**
* 計算每段弧度的中心座標
*
* @param degree 當前扇形中心度數
*/
private float[] calculatePosition(float degree) {
//因爲Math.sin(double a)中參數a不是度數而是弧度,因此須要將度數轉化爲弧度
//而Math.toRadians(degree)的做用就是將度數轉化爲弧度
//sin 一二正,三四負 sin(180-a)=sin(a)
//扇形弧線中心點距離圓心的x座標
float x = (float) (Math.sin(Math.toRadians(degree)) * radius);
//cos 一四正,二三負
//扇形弧線中心點距離圓心的y座標
float y = (float) (Math.cos(Math.toRadians(degree)) * radius);
//每段弧度的中心座標(扇形弧線中心點相對於view的座標)
float startX = centerX + x;
float startY = centerY - y;
float[] position = new float[2];
position[0] = startX;
position[1] = startY;
return position;
}
/**
* 繪製數據
*
* @param canvas 畫布
* @param degree 第i段弧線中心點相對於縱軸的夾角度數
* @param i 第i段弧線
* @param percent 數據百分比
*/
private void drawData(Canvas canvas, float degree, int i, float percent) {
//弧度中心座標
float startX = calculatePosition(degree)[0];
float startY = calculatePosition(degree)[1];
//獲取名稱文本大小
dataPaint.getTextBounds(names[i], 0, names[i].length(), dataTextBound);
// //繪製名稱數據,20爲縱座標偏移量
// canvas.drawText(names[i],
// startX - dataTextBound.width() / 2,
// startY + dataTextBound.height() / 2 - 20,
// dataPaint);
//
//
// //拼接百分比並獲取文本大小
// DecimalFormat df = new DecimalFormat("0.0");
// String percentString = df.format(percent * 100) + "%";
// dataPaint.getTextBounds(percentString, 0, percentString.length(), dataTextBound);
//
// //繪製百分比數據,20爲縱座標偏移量
// canvas.drawText(percentString,
// startX - dataTextBound.width() / 2,
// startY + dataTextBound.height() * 2 - 20,
// dataPaint);
}
/**
* 繪製扇形
*
* @param canvas 畫布
* @param startAngle 開始度數
* @param angle 扇形的度數
* @param color 顏色
*/
private void drawArc(Canvas canvas, float startAngle, float angle, int color) {
mArcPaint.setColor(color);
//-0.5和+0.5是爲了讓每一個扇形之間沒有間隙
canvas.drawArc(rectF, startAngle - 0.5f, angle + 0.5f, false, mArcPaint);
}
/**
* 生成隨機顏色
*/
private int randomColor() {
int red = random.nextInt(256);
int green = random.nextInt(256);
int blue = random.nextInt(256);
return Color.rgb(red, green, blue);
}
/**
* 設置數據
*
* @param numbers 數字數組
* @param names 名稱數組
*/
public void setData(int[] numbers, String[] names) {
sum = 0;
if (numbers == null || numbers.length == 0 || names == null || names.length == 0) {
return;
}
if (numbers.length != names.length) {
//名稱個數與數字個數不相等
return;
}
this.numbers = numbers;
this.names = names;
colors = new int[numbers.length];
for (int i = 0; i < this.numbers.length; i++) {
//計算總和
sum += numbers[i];
//隨機顏色
if(numbers.length == 3){
colors[0] = Color.rgb(43,218,97);
colors[1] = Color.rgb(43,218,204);
colors[2] = Color.rgb(228,91,73);
}else{
colors[i] = randomColor();
}
}
//計算總和數字的寬高
centerTextPaint.getTextBounds(sum + "", 0, (sum + "").length(), centerTextBound);
invalidate();
}
}