自定义view-手撸一个饼图

1、饼图可以应用在多方面,比如 财务类资金用途占比统计、生活类个人喜好占比、等等,待产品提出这样得效果,我们可以随意的绘制出来。下面我来一步步剖析饼图的绘制过程。如下图先看效果


image.png

2、第一步先分析一下这个饼图的思路,首先这个饼图是由多个扇形以及折线以及文字组成。可以分为三块来分别绘制。首先需要用到的知识点先大概说一下。

· 画扇形用到canvas.drawArc()或者用Path类下的path.arcTo() 都可以实现
· 画折线用drawLine()即可
· 画文字用drawText()即可
· 计算弧长上的坐标需要用到三角函数 cos 余弦、 sin正弦

3、我们直接来分析代码

/**
 * 饼图的颜色
 */
private int[] mColors = {Color.YELLOW, Color.RED, Color.GREEN, Color.BLUE, Color.GRAY, Color.LTGRAY};
/**
 * 初始化各个扇形的角度
 */
private float[] mPieAngles = {123, 73, 63, 53, 23, 13};
/**
 * 初始化文字
 */
private String[] texts = {"feng", "fang", "wei", "ran", "hello world", "some a bitch"};

/**
 * 扇形最大的间隔度数
 */
private int angleDash = 2;

/**
 * 扇形的半径
 */
private int mRadius = 200;

以上是该饼图所需要的一些初始化数据

4、先计算出view可用的宽和高方便平移坐标系,以及初始化扇形的外框矩形坐标

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    //view 的可用高度
    mViewHeight = h - getPaddingTop() - getPaddingBottom();
    //view 的可用宽度
    mViewWidth = w - getPaddingLeft() - getPaddingRight();
    //画扇形的矩形坐标
    mRectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
}

5、之后我们需要初始化扇形、折线、文字的画笔,以及坐标系原点

  private void init() {
    //扇形的画笔
    mPiePaint = new Paint();
    mPiePaint.setAntiAlias(true);
    mPiepath = new Path();
    //折线的画笔
    mLinePaint = new Paint();
    mLinePaint.setStrokeWidth(2);
    mLinePaint.setColor(Color.WHITE);
    mLinePaint.setAntiAlias(true);
    //文字的画笔
    mTextPaint = new Paint();
    mTextPaint.setAntiAlias(true);
    mTextPaint.setColor(Color.WHITE);
    mTextPaint.setTextSize(25);
    //标题的画笔
    mTitlePaint = new Paint();
    mTitlePaint.setTextSize(40);
    mTitlePaint.setAntiAlias(true);
    mTitlePaint.setTextAlign(Paint.Align.CENTER);
    mTitlePaint.setColor(Color.WHITE);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //将坐标原点平移到(mViewWidth / 2, mViewHeight / 2)位置处
    canvas.translate(mViewWidth / 2, mViewHeight / 2);
    //画文字和折线以及扇形
    drawPieAndLineAndText(canvas);
    //画标题
    drawTitle(canvas);
}

说明:将坐标系平移到view中心 便于之后的弧长的中点坐标的计算,下面正式进入核心代码

6、画扇形

private void drawPie(Canvas canvas, int i) {
    //画扇形
    if (i == 0) {
        mPiepath.moveTo(10, 10);
        mPiepath.arcTo(new RectF(mRectF.left + 10, mRectF.top + 10,
                mRectF.right + 10, mRectF.bottom + 10), startAngle, mPieAngles[i]);
    } else {
        mPiepath.moveTo(0, 0);
        mPiepath.arcTo(mRectF, startAngle, mPieAngles[i]);
    }
    mPiePaint.setColor(mColors[i]);
    canvas.drawPath(mPiepath, mPiePaint);
    mPiepath.reset();
    startAngle = (int) (startAngle + mPieAngles[i] + angleDash);
}

这里我需要解释一下,图示效果,有一个弧度最大的扇形有一个偏移效果,我这边是将path的起点坐标从原来的(0,0)变为(10,10),将该扇形的矩形轮廓坐标也对应的偏移了10个像素,即可达到偏移效果
这里的startAngle是每个扇形的起始绘制的角度,每绘制一个扇形,下一个扇形的起始绘制角度就是 上一个扇形的角度与上一个扇形的起始的角度以及扇形之间的间隔角度和。

7、画折线和文字 这里只贴出核心代码解释

        float xStart = (float) (mRadius * Math.cos(Math.toRadians(startAngle - angleDash - mPieAngles[i] / 2)));
        float yStart = (float) (mRadius * Math.sin(Math.toRadians(startAngle - angleDash - mPieAngles[i] / 2)));
        float xStop = (float) ((mRadius + lineFirstLength) * Math.cos(Math.toRadians(startAngle - angleDash - mPieAngles[i] / 2)));
        float yStop = (float) ((mRadius + lineFirstLength) * Math.sin(Math.toRadians(startAngle - angleDash - mPieAngles[i] / 2)));
        canvas.drawLine(xStart, yStart, xStop, yStop, mLinePaint);
        if (xStop > xStart) {
            canvas.drawLine(xStop, yStop, xStop + lineSecondLength, yStop, mLinePaint);
            mTextPaint.setTextAlign(Paint.Align.LEFT);
            canvas.drawText(texts[i], xStop + lineSecondLength + 10, yStop, mTextPaint);
        } else {
            canvas.drawLine(xStop, yStop, xStop - lineSecondLength, yStop, mLinePaint);
            mTextPaint.setTextAlign(Paint.Align.RIGHT);
            canvas.drawText(texts[i], xStop - lineSecondLength - 10, yStop, mTextPaint);
        }

根据三角函数很容易计算出,每个扇形的弧长中点坐标 即上面的xStart,yStart 然后根据同样的算法,将半径延长即可计算出第一段线段的终点坐标 即 xStop,yStop,根据这两个点即可画出第一段线段。

第二段线段就需要做一些判断了 根据第一段线段的走向,判断出第二段线段的走势,如何第一段是趋于向右的,那么第二段线段水平向右,反之向左。

画完两段线段之后再末尾 绘制对应的文字 (这里根据画笔paint的一个属性即可确定文字是从左向右还是从右向左)
mTextPaint.setTextAlign(Paint.Align.LEFT);

到此,简单的饼图就绘制完成了,其中主要弧长中点坐标的计算,以及三角函数和android的drawXXX()方法的结合使用

源码github地址:https://github.com/weiranqiaobo/pieDemo/tree/master

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,077评论 4 62
  • Nikki Haley Nimrata"Nikki"Haley(néeRandhawa, born January...
    RED_cc33阅读 430评论 0 0
  • AQTime AQTime简介 AQTime针对运行时分析:性能瓶颈、内存泄露、代码覆盖率、故障模拟,在影响产品质...
    龙翱天际阅读 610评论 0 0
  • 世间的人,有各种各样浩如烟海变化多端的,人的需要 有需要,就有交易,就有了生意 我满足你的需要,你给我钱,天经地义...
    傅李叶_aiden阅读 169评论 0 0
  • 事情的开始应该这样讲起,昨晚和大一时参加学生会而成为了挚友的男人女人们出去聚了餐,说说笑笑间谈起了最近的改变。大家...
    MH木子阅读 228评论 0 0