最近有朋友项目需要做饼图扇形图显示的内容,就简单做了一个demo
效果如下!
代码下载地址:
https://download.youkuaiyun.com/download/qq_38355313/10294797
首先自定义了一个类
package com.nxm.wordrecognition.nxm;
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.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import java.util.List;
/**
* Created by LK on 2018/3/15.
*
* @author LK
*/
public class PieChart extends View {
/**
* 画笔
*/
private Paint mPaint;
private Paint mTvPaint;
/**
* 饼状图宽高
*/
private int mWidth, mHeight;
/**
* 饼状图起始角度
*/
private float mStartAngle = 0f;
/**
* 动画时间
*/
private static final long ANIMATION_DURATION = 1000;
/**
* 用户数据
*/
private List<PieData> mData;
/**
* 绘制方式
*/
private int mDrawWay = PART;
public static final int PART = 0;//分布绘制
public static final int COUNT = 1;//连续绘制
private int centerX, centerY;//中心坐标
private int offset = 6;
/**
* 自定义动画
*/
private PieChartAnimation mAnimation;
private float sumValue = 0;//数据值的总和
public PieChart(Context context) {
super(context);
init();
}
public PieChart(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
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);//画笔为填充
mTvPaint = new Paint();
mTvPaint.setStyle(Paint.Style.FILL);
mTvPaint.setColor(Color.GRAY);
mTvPaint.setTextSize(30);
//初始化动画
mAnimation = new PieChartAnimation();
mAnimation.setDuration(ANIMATION_DURATION);
}
/**
* 设置起始角度
*
* @param mStartAngle
*/
public PieChart setmStartAngle(float mStartAngle) {
this.mStartAngle = mStartAngle;
invalidate();//刷新
return this;
}
/**
* 设置数据
*
* @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();
}
/**
* 总和
*
* @param sumValue
*/
public PieChart setSumValue(float sumValue) {
this.sumValue = sumValue;
invalidate();//刷新
return this;
}
/**
* 初始化数据
*
* @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();
data.setColor(COLORS[i]);
}
/**
* 计算百分比和角度
*/
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) {
super.onDraw(canvas);
if (mData == null) {
return;
}
centerX = (getRight() - getLeft()) / 2;
centerY = (getBottom() - getTop()) / 2;
//1.移动画布到中心点
canvas.translate(mWidth / 2, mHeight / 2);
//2.设置当前起始角度
float currentStartAngle = mStartAngle;
//3.确定饼图的半径
float r = (float) (Math.min(mWidth, mHeight) / 3);
float r1 = r / 2;
float r2 = r / 1.8f;
float stopX = 0;
float stopY = 0;
//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.绘制饼图
canvas.drawArc(rectF, currentStartAngle, data.getAngle(), true, mPaint);
//7.绘制下一块扇形时先将角度加上当前扇形的角度
mPaint.setColor(data.getColor());
stopX = (float) ((r + 30) * Math.cos((2 * currentStartAngle + data.getAngle()) / 2 * Math.PI / 180));
stopY = (float) ((r + 30) * Math.sin((2 * currentStartAngle + data.getAngle()) / 2 * Math.PI / 180));
//canvas.drawPoint(stopX, stopY, TPaint);
canvas.drawCircle(stopX, stopY, 10, mPaint);
currentStartAngle += data.getAngle();
//画横线
int dx;
// 判断横线是画在左边还是右边
int endX;
if (stopX > 0) {
endX = (centerX - getPaddingRight() - 20);
} else {
endX = (-centerX + getPaddingLeft() + 20);
}
//画横线
canvas.drawLine(stopX, stopY,
endX, stopY, mPaint);
dx = (int) (endX - stopX);
//测量文字大小
Rect rect = new Rect();
String text = data.getText();
mTvPaint.getTextBounds(text, 0, text.length(), rect);
int w = rect.width();
int h = rect.height();
canvas.drawText(text, 0, text.length(), dx > 0 ? endX - offset - w : endX + offset, stopY + h + offset, mTvPaint);
Rect rect2 = new Rect();
String value = data.getPercentage();
mTvPaint.getTextBounds(value, 0, value.length(), rect2);
int w2 = rect2.width();
int h2 = rect2.height();
canvas.drawText(value, 0, value.length(), dx > 0 ? endX - offset - w2 : endX + offset, stopY - offset, mTvPaint);
}
//绘制中心空白处
mPaint.setColor(0x11000000);
canvas.drawArc(rectF2, currentStartAngle, 360f, true, mPaint);
//绘制中心阴影部分
mPaint.setColor(Color.parseColor("#FFFFFF"));
canvas.drawArc(rectF1, currentStartAngle, 360f, true, mPaint);
//绘制文字
mPaint.setColor(0xEEFF4567);
mPaint.setTextSize(80);
// 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 final static int[] COLORS = {
Color.rgb(192, 255, 140), Color.rgb(140, 234, 255)
, Color.rgb(255, 247, 140), Color.rgb(255, 208, 140)
, Color.rgb(140, 234, 255), Color.rgb(255, 140, 157)
, Color.rgb(45, 192, 252), Color.rgb(53, 194, 209)
, Color.rgb(52, 152, 219), Color.rgb(255, 255, 240)};
}
其次定义一个数据模型bean
package com.nxm.wordrecognition.nxm;
import android.util.Log;
import java.text.DecimalFormat;
/**
* Created by LK on 2018/3/15.
*
* @author LK
*/
public class PieData {
private String text;
private float value;
private float Angle;
private float Percentage;
private int color;
private float CurrentStartAngle;
public int getColor() {
return color;
}
public void setColor(int color) {
this.color = color;
}
public float getCurrentStartAngle() {
return CurrentStartAngle;
}
public void setCurrentStartAngle(float currentStartAngle) {
CurrentStartAngle = currentStartAngle;
}
public String getPercentage() {
DecimalFormat decimalFormat = new DecimalFormat("00.0");
Log.e("Lzx", Percentage + "");
return decimalFormat.format(Percentage*100) + "%";
}
public void setPercentage(float percentage) {
//保留两位小数点
Percentage = percentage;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public float getValue() {
return value;
}
public void setValue(float value) {
this.value = value;
}
public float getAngle() {
return Angle;
}
public void setAngle(float angle) {
Angle = angle;
}
public PieData() {
}
public PieData(float value) {
this.value = value;
}
public PieData(String text, float value) {
this.text = text;
this.value = value;
}
}
然后即可在layout中插入该view使用了
public class MainActivity extends AppCompatActivity {
private PieChart mPieChart;
private List<PieData> pieData;
public static final int COUNT = 1;//连续绘制
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPieChart = f(R.id.mPieChart);
pieData = new ArrayList<>();
for (int i = 0; i < 6; i++) {
pieData.add(new PieData("text" + i, (float) Math.random() * 90));
}
mPieChart.setData(pieData, COUNT);
}
public <T extends View> T f(int id) {
return (T) findViewById(id);
}
}