Android自定义View,画一个好看带延长线的饼状图

本文介绍了如何在Android中自定义View来实现一个带延长线的饼状图,包括绘制思路和详细步骤。从确定饼图圆心、绘制扇形、添加中心空洞,到计算延长点、绘制圈、线和文字,最后处理宽高适配,通过正余弦算法实现设计稿中的效果。完整代码可在作者的GitHub项目中查看。
摘要由CSDN通过智能技术生成

前言

在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呢?因为在接下来的饼图绘制中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值