分析结构
1.数字
2.数据柱状图
3.分隔线
4.图标
自定义View 主要重写onMeasure()、onDraw()方法,如果自定义ViewGroup的那么还需要考虑onLayout()方法。
首先在构造方法中 初始下各个参数 如:Paint、分隔线颜色、文字颜色、文字高度、文字与柱状图间距等等 目前些数值都是写死的,造轮子可以使用attrs声明属性,进行布局配置参数,
Paint测量文字
Paint.getTextBounds(text,start,end,rect) 方法可以获取到text指定的start->end的宽高,存入rect对象里面
Paint.measureText(text)方法可以获取到text的宽度值
实际应用中 同一串文字 使用两个方法测量出来宽度是有差距的
measureText(text)返回的宽度信息会比getTextBounds(text,start,end,rect) 略大一些,原因是measureText(text)会在字符串的两侧增加一些预先值,而getTextBounds(text,start,end,rect) 则计算给定字符start->end的最小边界值
onMeasure(int widthMeasureSpec, int heightMeasureSpec)
负责测量View本身所占的宽高尺寸,widthMeasureSpec,heightMeasureSpec封装了测量模式和测量值。
通过MeasureSpec.getMode(widthMeasureSpec/heightMeasureSpec)和MeasureSpec.getSize(widthMeasureSpec/heightMeasureSpec)
获取到View的测量模式和测量值
测量模式分为三种:
EXACTLY:宽高值设置为:具体值(xxdp)、match_parent、约束布局定义的占比值等等的模式,该模式取出的值是精确的尺寸;
AT_MOST:宽高值设置为:wrap_content时的模式,该模式取出的值是View可获得的最大值;
UNSPECIFIED:未指定模式,比较少使用到;一般会是父控件为ScrollView时会传入该模式。
自定义的柱状图 在onMeasure()中 获取到控件的宽高、当高度为UNSPECIFIED/AT_MOST时设定一个默认高度,防止高度过高
同时也计算出 分隔线、图标、柱状图的顶部 的位置
接下来进入draw() 环节了
前提:定义了一个柱形数据集合 用于收集柱形数据
onDraw()方法 遍历 取出每个柱形对面进行绘制
1.绘制图标 drawBitmap
这里有做一个处理:缩放bitmap到预设大小
得到Bitmap后
drawBitmap(bitmap,left,top,paint)进行绘制图标
drawRect(rectF,paint)进行柱形绘制
drawText(s,x,y,paint)进行文字绘制
绘制柱形图时 有想过绘制圆角的需求,可以使用canvas.drawRoundRect()绘制,但是这样绘制出来的是四个角都是圆角,解决方案1.用 分隔线 盖住底部的圆角 2.使用path绘制柱形
首个边距是单独的
后续边距是图标的宽度加到下一个图标的宽度,柱形、文字是一样的算法
接着drawLine(startX,startY,stopX,stopY,paint)绘制分隔线
这样就算是完成了整个绘制的流程了
再开放一个方法 用于设置column数据集合进行数据填充就能得到一枚柱状图表了
。。。这样设置后图表显示感觉很唐突,那么我想让它能动态从零增长到最大值就需要做一些运算,然后再通过postInvalidate()进行更新显示了
postInvalidate()和invalidate()都是用于刷新View,invalidate()直接应用UI线程中,而postInvalidate()应用于非UI线程中,实际上通过源码可知 postInvalidate()最终也是调用了invalidate()方法
主要步骤
把柱子高度 拆分出一定的份额,然后进行数值递增,最后再刷新View…done!