前言
在Android中,图表的实现是比较麻烦的,基本只能通过自定义View来实现。目前Github上有一些集成度高功能性强的三方库,比如MPAndroidChart等。但三方库虽然强大,定制性总是有限的,在项目中为了达成一些特别需求,就要靠我们自己去画啦。虽然费点时间,不过计算各种绘制点的位置的过程还是很有趣的。我个人对于自定义View这部分只是小有了解,所以大家如果对本文中的代码有什么改进意见,欢迎在评论区或者我的github项目上提issues出来啦~
绘制思路
先来看一下,在项目中设计师给到我要实现的样子:
无视设计师画图时数字和占比不符的偷懒,可以看到这是一个普通的饼状图加上延长线、文字描述和一些圈圈点点,那么整理一下大致的绘制思路,我的想法是:
1.绘制饼状图
确定饼状图所处的正方形区域,找出圆点
通过drawArc绘制扇区,绘制出饼图的各个部分
中间画一个圆,让饼图变为只有外面一圈
2.绘制饼图外的点、圈、线、字
点的角度处于每个圆弧的半分处,通过正余弦算出点的位置
以点为圆心画圈
按照四个象限,不同象限以不同角度从圈边延长出线
以线的终点对齐加上字
2.给自定义View增加空间,以避免延长线和字显示不全
主要用到了数学中坐标系象限的概念和正余弦的算法,看着有点绕,确实也是挺绕的,接下来分步骤详细描述吧。
绘制饼图
首先我们需要存储各个饼图所需要的属性:
public class PieEntry {
//颜色
private int color;
//比分比
private float percentage;
//条目名
private String label;
//扇区起始角度
private float currentStartAngle;
//扇区总角度
private float sweepAngle;
//省略get&set
}
在绘制饼图中,我们只需要颜色、百分比就够了,其他的在后面的步骤才会用到。
确定圆点
在布局文件中,我们将自定义View的宽度设为match_paren,高度设为300dp,并添加一个浅色作为背景色。
饼图作为一个圆,那么在绘制这个圆前,我们先找出圆心的位置,并将其作为整个View的原点,即坐标(0,0)的位置。
在这里我向View中添加了坐标轴和原点的辅助线,作为指示用。
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//获取实际View的宽高
mTotalWidth = w - getPaddingStart() - getPaddingEnd();
mTotalHeight = h - getPaddingTop() - getPaddingBottom();
//绘制饼图所处的正方形RectF
initRectF();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//将坐标中心设到View的中心
canvas.translate(mTotalWidth / 2, mTotalHeight / 2);
//draw...
}
创建正方形RectF,确定饼图半径
在确定圆心并将其设为坐标原点后,创建一个边长等于View短边长的正方形RectF:
private void initRectF() {
float shortSideLength;
//取短边 作为饼图所在正方形的边长
shortSideLength = (mTotalHeight < mTotalWidth) ? mTotalHeight : mTotalWidth;
//除以2即为饼图的半径
mRadius = shortSideLength / 2;
//设置RectF的坐标
mRectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
}
设置paint颜色为红色,将这个Rect通过canvas.drawRect(mRectF, mPaint);在View中绘制出来,可以看到其边长是和高度一致的:
那么为什么需要创建这个正方形RectF呢?因为在接下来的饼图绘制中