Android条形图绘制以及加入动画,并且支持水平滑动

闲话

Android 图表的绘制,无非是view的绘制,只有掌握了view的绘制流程,那么一个条形图,也没有什么可难绘制的,那为什么会有人觉得比较难呢,其实是自己内心里惧怕他,于是每次出现图表需求,想都不用想就选择第三方的,也就是别人写好的,当然,这也没有什么,大家都会用的,也不只是你一个人在用,目前在github上star最多的可能就是MPAndroidChart了,做的的确很强大,但是再强大,有时候也会有那么一丢丢的不符合我们自己的需求,这个时候,真是让人哭笑不得啊,用的话,又不能达到产品的需求,不用吧,自己好像又没有什么思路,于是僵住了。

我花了点时间大致的看了下MPAndroidChart源码,的确内容很多,今天,就用自己的思想以及MPAndroidChart的思想相结合来写一个比较简单的条形图,这样也是对绘制view的一次学习吧

效果

  1. 不可滑动效果:
不可滑动
  1. 可滑动效果:
可滑动

图片看起来有点失真,还伴随点卡顿,这是由于录像是电脑和手机连接不稳定造成的,真实的动画是不会有任何卡顿的。

理清思路

首先我们得理清思路,如何才能绘制出一个条形图,不能连思路都没有就去做,这样真的很难下手。

1. 初始化操作

首先,图表是自定义view,继承自view,所以该重写的方法都要重写。

  1. 当图表创建时,我们都需要准备什么,第一个当然是画笔Paint了,这个时候我们只需要对画笔进行初始化,什么颜色啊,填充方式啊等等。
  2. 除了初始化画笔Paint外,我们还需要初始化的,就是动画了,因为我们需要给条形图加入动画,这个时候,问题来了,动画和条形图如何结合起来?
  3. 能让条形图动起来的动画当然是ValueAnimator或者ObjectAnimator了,这两个动画其实是一个东西,最终都是ValueAnimator,所以用哪个其实都可以实现,我用的是ObjectAnimator,因为MPAndroidChart也用的是ObjectAnimator。
  4. 究竟动画怎么才能和条形图结合呢?
 private void init() {

        //初始化动画
        mAnimator = new ChartAnimator(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                postInvalidate();
            }
        });

        mBound = new Rect();


        //柱子画笔
        mChartPaint = new Paint();
        mChartPaint.setAntiAlias(true);
        mChartPaint.setColor(Color.parseColor(chartColor));


        //线画笔
        linePaint = new Paint();
        linePaint.setAntiAlias(true);
        linePaint.setColor(Color.parseColor(lineColor));

        //x纵坐标 画笔
        textXpaint = new Paint();
        textXpaint.setAntiAlias(true);
        textXpaint.setTextSize(27f);
        textXpaint.setTextAlign(Paint.Align.CENTER);
        textXpaint.setColor(Color.parseColor(textColor));

        //Y纵坐标 画笔
        textYpaint = new Paint();
        textYpaint.setAntiAlias(true);
        textYpaint.setTextSize(28f);
        textYpaint.setTextAlign(Paint.Align.LEFT);
        textYpaint.setColor(Color.parseColor(textColor));

        //无数据时的画笔
        noDataPaint = new Paint();
        noDataPaint.setAntiAlias(true);
        noDataPaint.setColor(Color.parseColor(noDataColor));
        noDataPaint.setStyle(Paint.Style.FILL);
    }

2. 动画和条形图的结合

大家都知道ValueAnimator动画,是将两个数经过计算之后,会得到一系列的数值,这些数值都会在这两个值得区间,那么这个时候,就能将生成的这些值和条形图的高度联系到一起,ValueAnimator的值是从0到1的,生成的全是Float类型的值,可以理解为百分数,也就是从0%到100%,这个时候条形图的动画也就能实现了,每个条形图的高度都从0开始绘制,一直绘制到他的真实高度,绘制完成后,动画自然也就结束了,条形图的高度占这个view的高度的百分比,也就是占整个图表控件的高度的百分比是可以算出来的。

3. 测量高度

  1. 在onLayout方法里,可以得到view的高度和宽度,因为我们需要在后面计算每个条形图占整个控件高度的百分比

  2. 在onLayout方法里也需要计算条形图的宽度和间隙,以及横纵坐标起始位置坐标

 @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mWidth = getWidth();
        mHeight = getHeight() - paddingTop;

        chartWidth = mWidth - outSpace;

        //每个柱子宽度
        barWidth = (int) (chartWidth * barPercent);
        interval = (int) (chartWidth * intevalPercent);

        //所有柱子宽度 之和
        allBarwidth = horizontalList.size() * barWidth;
        //所有间隔宽 之和
        allInteval = (horizontalList.size() - 1) * interval;

        //所有柱子和间隔的宽度
        allChartWidth = allBarwidth + allInteval;

        //柱子开始的横坐标

        startChart = outSpace + (chartWidth / 2f - allChartWidth / 2f);
        //横坐标

        textStart = startChart + (barWidth / 2f);

    }

5. 开始绘制

  1. view的绘制全在onDraw方法里,这个时候就用到onDraw方法中的canvas了,条形图其实也就是矩形,所以也很好绘制,这个时候,我们需要了解的就是canvas的方法,他都能绘制些什么,方法中的参数又是什么意思并且代表着什么,只有搞清楚了这些,我们才能正式开始下手绘制,否则,我们还是无从下手。
  2. canvas.drawRect(),这个方法其实才是我们重点要掌握的,他就是绘制矩形的方法,首先,你需要知道,他的参数的意义
  3. 他需要的参数为:(float left, float top, float right, float bottom,Paint paint ),乍一看,参数太多,看都不想看了,别着急,他很简单的,只不过就是坐标而已,上下左右嘛,这有什么难的,那么这又分别代表着什么呢,搞清楚这些我们才好下手呀。
  4. left表示矩形的左边到view最左边的距离,而不是屏幕的左边,这个要搞清楚,top也就表示着矩形的上边到view的顶部距离,而不是屏幕顶部,right是矩形的右边到view的左边距离,bottom是矩形的下边到view的顶部的距离
  5. 只要你搞清楚了上面这些,绘制图表不再是什么难题了,剩下的只是坐标的计算和柱子宽度,高度的计算了
  6. 下面是ondraw方法
 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        float lineInterval = (mHeight - bottomHeight) / 4f; //横线之间的间距  纵向
        float textHeight = mHeight + paddingTop - bottomHeight;//横坐标高度

        //画线
        drawLine(canvas, lineInterval, textHeight);

        //画纵坐标
        drawYtext(canvas, lineInterval, textHeight);

        //画横坐标
        float textTempStart = textStart;

        drawXtext(canvas, textTempStart);


        float chartTempStart = startChart;

        float size = (mHeight - bottomHeight) / 100f; //比例

        //画柱子
        drawBar(canvas, chartTempStart, size);

    }

需要理解的地方

  1. 在view进行初始化的时候,我们初始化了一个ChartAnimator,其实是ObjectAnimator将0-1内生成的所有数字给了他,方便在view里得到这些变化的值。
  2. 在初始化的时候,我们对动画做了监听,当他更新的时候,我们就调用了一下postInvalidate(),这句话就是让view执行ondraw方法,通过变量来增加条形图的高度。
  3. 最后还是条形图宽度的问题,我是这样设计的,当条形图的数量大于6时,那么所有的条形图的宽度将平分整个view的宽度,然后将计算后的值得30%作为条形图的间隔,剩下的70%的宽度就是条形图的宽度,绘制是从左向右绘制,当条形图的数量小于6或者等于6时,我将所有的条形图绘制到了整个表的中间,宽度怎么平分的大家可以查看源码,具体的就不说了
  4. 水平滑动用到了Android的手势,有兴趣的可以看下,暂时不说这块

源码下载

  1. 文章只贴出了一部分源码,更详细的源码,请查看我的demo
  2. 获取源码方式:在公众号:AppCode公众号内回复关键字“条形图”,即可拿到源码的下载链接。
  3. 扫描下面的二维码,即可关注AppCode公众号
AppCode
AppCode
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容