
效果图

分析:从上面效果图我们可以知道该View由饼图、右侧的矩形和文字组成,接下来我们具体分析如何用代码实现。
- 首先我们肯定需要构建一个实体类,用来描述自定义View时需要的属性值;
public class PieChartBean {
public int mColor; //填充的颜色值
public float sweepAngle; //绘制圆弧是用到的sweepAngle,构建实例的时候不需要赋值
public String name; //文字的内容
public float value; //具体数值,用来计算sweepAngle和文字右侧的数值
public PieChartBean(int color, String name, float value) {
mColor = color;
this.name = name;
this.value = value;
}
}
- 绘制View
我们可以利用canvas的drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint) 绘制左侧的饼图,该方法我们需要关注的参数是开始角度startAngle和扫过的角度值sweepAngle,而sweepAngle可以有startAngle计算得知。矩形我们可以用方法 drawRect(RectF rect, Paint paint)绘制,文字我们可以用drawText(String text, float x, float y,Paint paint) 绘制,下面看看完整代码:
public class PieChartView extends View {
private Context mContext;
private ArrayList<PieChartBean> beanList;
private RectF mRectF;
private Paint mPaint;
private int mRWidth;
private int mRHeight;
private int diameter;
private float sumValue = 0;
private float startRotateDegree;//每个圆弧的起始角度
private RectF iRectF;
private int mMargin = 40;//矩形和圆的距离
private int mRectWidth = 100;//矩形宽度
private int textY;//绘制文字的y坐标
private int mRectHeight = 50;//矩形高度
public PieChartView(Context context) {
//在代码中new PieChartView会调用这个构造函数
this(context,null);
}
public PieChartView(Context context, AttributeSet attrs) {
//InflateLayoutManager时会调用这个构造函数
this(context, attrs, 0);
}
public PieChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
init();
}
private void init() {
beanList = new ArrayList<>();
mRectF = new RectF();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int wMode = MeasureSpec.getMode(widthMeasureSpec);
int hMode = MeasureSpec.getMode(heightMeasureSpec);
int wSize = MeasureSpec.getSize(widthMeasureSpec);
int hSize = MeasureSpec.getSize(heightMeasureSpec);
switch (wMode){
case MeasureSpec.EXACTLY:
//相当于match_parent或者一个具体值
mRWidth = wSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED://很少会用到不考虑
//相当于wrap_content
mRWidth = (int) DpUtil.dp2px(mContext,400f);
break;
}
switch (hMode){
case MeasureSpec.EXACTLY:
//相当于match_parent或者一个具体值
mRHeight = hSize;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED://很少会用到不考虑
//相当于wrap_content
mRHeight = (int) DpUtil.dp2px(mContext,200f);
break;
}
setMeasuredDimension(mRWidth,mRHeight);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
diameter = Math.min(mRWidth,mRHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRectF.set(0,0,diameter,diameter);
canvas.translate((mRWidth-diameter)/8,(mRHeight - diameter) / 2);
if (beanList.size() > 0 && Float.compare(sumValue,0.0f) != 0){
for (int i = 0; i < beanList.size(); i++) {
PieChartBean pieChartBean = beanList.get(i);
//画圆弧
mPaint.setColor(pieChartBean.mColor);
canvas.drawArc(mRectF,startRotateDegree,pieChartBean.sweepAngle,true,mPaint);
//下一个圆弧的起始角度
startRotateDegree += pieChartBean.sweepAngle;
//画矩形和文字
drawRectAndText(canvas,pieChartBean);
}
}
//绘制完之后必须要让textY置为0,否则会有问题的
textY = 0;
}
private void drawRectAndText(Canvas canvas, PieChartBean pieChartBean) {
iRectF = new RectF();
//设置画矩形的范围
float left = diameter + mMargin;
float right = diameter + mMargin + mRectWidth;
float bottom = textY + mRectHeight;
iRectF.set(left,textY,right,bottom);
canvas.drawRect(iRectF,mPaint);
//设置颜色
mPaint.setColor(pieChartBean.mColor);
//设置文字大小
mPaint.setTextSize(40);
//画文字
canvas.drawText(pieChartBean.name + "("+new DecimalFormat(".00").format(pieChartBean.value/sumValue*100)+"%)"
,right + 10, textY + 40, mPaint);
textY += mRectHeight;
}
/**
* 饼状图添加数据
* @param list
*/
public void setData(List<PieChartBean> list){
if (list == null || list.size()<=0)
return;
//计算总值
for (int i = 0; i < list.size(); i++) {
PieChartBean pieChartBean = list.get(i);
sumValue += pieChartBean.value;
}
//计算每条数据的sweepAngle
for (int i = 0; i < list.size(); i++) {
PieChartBean pieChartBean = list.get(i);
pieChartBean.sweepAngle = pieChartBean.value / sumValue * 360;
beanList.add(pieChartBean);
}
//刷新界面
invalidate();
}
/**
* 设置绘制第一个圆弧的起始角度
* @param startDegree
*/
public void setStartDegree(float startDegree){
this.startRotateDegree = startDegree;
invalidate();
}
}
- 实体类的构建并给view的数据赋值
private void initPieData() {
PieChartBean bean1 = new PieChartBean(Color.parseColor("#f14033"), "郭瑜", 80);
PieChartBean bean2 = new PieChartBean(Color.parseColor("#e6870b"), "李旭", 30);
PieChartBean bean3 = new PieChartBean(Color.parseColor("#0fc2c2"), "南南", 50);
PieChartBean bean4 = new PieChartBean(Color.parseColor("#29b117"), "石瑾", 60);
PieChartBean bean5 = new PieChartBean(Color.parseColor("#1b75e4"), "羊角", 20);
PieChartBean bean6 = new PieChartBean(Color.parseColor("#e746d4"), "亚琴", 30);
PieChartBean bean7 = new PieChartBean(Color.parseColor("#df0d30"), "贾祺", 60);
List<PieChartBean> list = new ArrayList<>();
list.add(bean1);
list.add(bean2);
list.add(bean3);
list.add(bean4);
list.add(bean5);
list.add(bean6);
list.add(bean7);
//设置绘制圆弧的起始角度
mPieChartView.setStartDegree(90f);
mPieChartView.setData(list);
}
源码都在这上面在此就不贴了。
网友评论