文章版權聲明:http://blog.csdn.net/qq_23179075/article/details/61926408
源碼下載下傳:http://download.csdn.net/detail/qq_23179075/9779799
GitHub:https://github.com/azhengyongqin/PieChart
先上圖:
/**
* 時 間: 2017/3/13
* 作 者: 鄭亮
* Q Q : 1023007219
*/
public class PieChart extends View {
/**
* 自定義顔色
*/
private static int[] mColors = {
0xFF323232,
0xFFCFB054,
0xFFDA8A8A,
0xFFC89FC2,
0xFF8AD3D2,
0xFF7DB3CB,
0xFF78899E,
0xFF62AD98,
0xFFB8A690,
0xFFA1B060,
0xFFD08E76
};
/**
* 畫筆
*/
private Paint mPaint;
/**
* 餅狀圖寬高
*/
private int mWidth, mHeight;
/**
* 餅狀圖起始角度
*/
private float mStartAngle = 0f;
/**
* 使用者資料
*/
private List<PieData> mData;
/**
* 動畫時間
*/
private static final long ANIMATION_DURATION = 1000;
/**
* 自定義動畫
*/
private PieChartAnimation mAnimation;
/**
* 繪制方式
*/
private int mDrawWay = PART;
public static final int PART = 0;//分布繪制
public static final int COUNT = 1;//連續繪制
public PieChart(Context context) {
this(context, null);
}
public PieChart(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PieChart(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* 初始化資料
*/
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setAntiAlias(true);//抗鋸齒
mPaint.setDither(true);//防止抖動
mPaint.setStyle(Paint.Style.FILL);//畫筆為填充
//初始化動畫
mAnimation = new PieChartAnimation();
mAnimation.setDuration(ANIMATION_DURATION);
}
/**
* 設定起始角度
*
* @param mStartAngle
*/
public void setmStartAngle(float mStartAngle) {
this.mStartAngle = mStartAngle;
invalidate();//重新整理
}
/**
* 設定資料
*
* @param mData
*/
public void setData(List<PieData> mData) {
setmData(mData);
}
/**
* 設定資料和繪制方式
*
* @param mData
*/
public void setData(List<PieData> mData, int mDrawWay) {
setmData(mData);
this.mDrawWay = mDrawWay;
}
/**
* 設定資料
*
* @param mData
*/
private void setmData(List<PieData> mData) {
sumValue = 0;
this.mData = mData;
initData(mData);
startAnimation(mAnimation);
invalidate();
}
float sumValue = 0;//資料值的總和
/**
* 初始化資料
*
* @param mData
*/
private void initData(List<PieData> mData) {
if (mData == null || mData.size() == 0) {
return;
}
/**
* 計算資料總和确定顔色
*/
for (int i = 0; i < mData.size(); i++) {
PieData data = mData.get(i);
sumValue += data.getValue();
int j = i % mColors.length;//設定顔色
data.setColor(mColors[j]);
}
/**
* 計算百分比和角度
*/
float currentStartAngle = mStartAngle;
for (int i = 0; i < mData.size(); i++) {
PieData data = mData.get(i);
data.setCurrentStartAngle(currentStartAngle);
//通過總和來計算百分比
float percentage = data.getValue() / sumValue;
//通過百分比來計算對應的角度
float angle = percentage * 360;
//設定使用者資料
data.setPercentage(percentage);
data.setAngle(angle);
currentStartAngle += angle;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mWidth = w;
mHeight = h;
}
@Override
protected void onDraw(Canvas canvas) {
if (mData == null) {
return;
}
//1.移動畫布到中心點
canvas.translate(mWidth / 2, mHeight / 2);
//2.設定目前起始角度
float currentStartAngle = mStartAngle;
//3.确定餅圖的半徑
float r = (float) (Math.min(mWidth, mHeight) / 2 * 0.95);
float r1 = r / 2;
float r2 = r / 1.8f;
//4.确定餅圖的矩形大小
RectF rectF = new RectF(-r, -r, r, r);
RectF rectF1 = new RectF(-r1, -r1, r1, r1);
RectF rectF2 = new RectF(-r2, -r2, r2, r2);
for (int i = 0; i < mData.size(); i++) {
PieData data = mData.get(i);
//5.設定顔色
mPaint.setColor(data.getColor());
//6.繪制餅圖
if (mDrawWay == PART) {
canvas.drawArc(rectF, data.getCurrentStartAngle(), data.getAngle(), true, mPaint);
} else if (mDrawWay == COUNT) {
canvas.drawArc(rectF, currentStartAngle, data.getAngle(), true, mPaint);
//7.繪制下一塊扇形時先将角度加上目前扇形的角度
currentStartAngle += data.getAngle();
}
}
//繪制中心空白處
mPaint.setColor(0x33000000);
canvas.drawArc(rectF2, currentStartAngle, 360f, true, mPaint);
//繪制中心陰影部分
mPaint.setColor(0xEEFFFFFF);
canvas.drawArc(rectF1, currentStartAngle, 360f, true, mPaint);
//繪制文字
mPaint.setColor(0xEEFF4567);
mPaint.setTextSize(80);
String str = "印象丶亮仔";
Rect textRect = new Rect();
mPaint.getTextBounds(str, 0, str.length(), textRect);
canvas.drawText("印象丶亮仔", -textRect.width() / 2, 0, mPaint);
}
}
自定義動畫:
/**
* 自定義動畫
*/
public class PieChartAnimation extends Animation {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
if (interpolatedTime < 1.0f) {
for (int i = 0; i < mData.size(); i++) {
PieData data = mData.get(i);
//通過總和來計算百分比
float percentage = data.getValue() / sumValue;
//通過百分比來計算對應的角度
float angle = percentage * 360;
//根據插入時間來計算角度
angle = angle * interpolatedTime;
data.setAngle(angle);
}
} else {//預設顯示效果
for (int i = 0; i < mData.size(); i++) {
//通過總和來計算百分比
PieData data = mData.get(i);
float percentage = data.getValue() / sumValue;
//通過百分比來計算對應的角度
float angle = percentage * 360;
data.setPercentage(percentage);
data.setAngle(angle);
}
}
invalidate();
}
}
使用:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private com.oeynet.customview.view.PieChart picchart;
private List<PieData> mDatas = new ArrayList<>();
private Button btnpart;
private Button btncount;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initData();
initListener();
}
private void initListener() {
this.btncount.setOnClickListener(this);
this.btnpart.setOnClickListener(this);
}
private void initViews() {
this.picchart = (PieChart) findViewById(R.id.pic_chart);
this.btncount = (Button) findViewById(R.id.btn_count);
this.btnpart = (Button) findViewById(R.id.btn_part);
}
private void initData() {
for (int i = 0; i < 6; i++) {
mDatas.add(new PieData((float) (10+Math.random()*90)));
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_count:
picchart.setmStartAngle(45);
picchart.setData(mDatas, PieChart.COUNT);
break;
case R.id.btn_part:
picchart.setmStartAngle(180);
picchart.setData(mDatas, PieChart.PART);
break;
}
}
}