上一篇中介绍了如何实现自定义View的流程。那么,在这一篇中我们就动手打造一个简单的运动步数的自定义View。可以看一下gif图展示了本次的运动步数的效果。

这里的效果,我想大部分人都见过。下面来看一下具体的实现过程。
开始
分析
通过gif图,我们可以对上图进行拆解。图中一共四个元素。分别是:最底层的弧线、动态显示的步数弧线、记录当前步数的文字、“步数”文字。整个拆解之后,就很容易了,我们只需要一步一步的绘制,就能得到效果了。至于动态的显示步数,则需要用到属性动画来处理。下面我们来一步一步实现。
自定义属性
在values目录下新建attrs.xml文件。在其中定义自己用得上的属性。
|
|
得到自定义属性
这里直接继承View,自己写这么一个效果。
|
|
得到上面的属性后,就可以用各个属性了。
初始化画笔
|
|
可以这样获取View的宽高,由于我们的View只是变化一次,所以onSizeChanged()只会调用一次。
|
|
在onDraw()中绘制
这一步是整个View的关键,这一步你就可以自己设计了。
|
|
以上就是四个元素的绘制,其中都是对坐标的计算,然后调用canvas来进行图形的绘制。
最底下的弧形不用过多介绍,其中
ArcRectF = new RectF(centerX - mRadius, centerY - mRadius, centerX + mRadius, centerY + mRadius);
是这个样子的。由于最上面的圆弧需要动态显示,所以这里可以对外提供两个方法。来对当前的最大步数,以及当前的步数进行设置。
|
|
之后,需要用到属性动画,我们仍然是暴露到外面。因为,只有调用者才知道该设置多少参数。
|
|
这里的invalidate()方法会不断的调用ondraw()方法,不断地重绘,达到整个动态效果。
所以,percent = currentAngleLength / maxStpes;就是当前的步数百分比。
- 绘制当前的步数文字,这里也是动态显示的。123456789String string = (int) currentAngleLength + "";// 测量文字的宽高Rect textBounds = new Rect();mTextPaint.getTextBounds(string, 0, string.length(), textBounds);int dx = -textBounds.width() / 2;// 获取画笔的FontMetricsPaint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();// 计算文字的基线int baseLine = (int) ((fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom);
currentAngleLength 是在属性动画中不断返回的进度值。转化成String类型后,就成字符串了,就可以用canvas绘制到屏幕上了。通过mTextPaint.getTextBounds()就可以完成对字符串的测量,然后得到width,由于坐标系原点在屏幕中心。所以这里这样处理int dx = -textBounds.width() / 2;。从dx开始绘制,绘制长度为string字符串的长度。然后借助 Paint.FontMetrics得到字符串的高度,这里之所以使用 Paint.FontMetrics是因为 Paint.FontMetrics中bottom是测量给定文本大小下字体中最低字形的最大距离,而top是在给定文本大小的字体中最高字形的基线上方的最大距离。而getTextBounds()返回的bottom以及top是不会这样的。所以使用了Paint.FontMetrics。这里baseLine的计算,其实大部分绘制文字时都需要这样计算,baseLine就是整个文本的基线,也就是整个文本的最底端。这里坐标系原点在屏幕中心,通过(fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom,就可以得到(文本高度/2)这么一个的正值。你可以自己计算一下。毕竟我的数学也不好╮(╯﹏╰)╭。。。之后canvas.drawText(string, dx, baseLine, mTextPaint);就可以了。为了让文本在正中心,由于坐标系在屏幕中心,我们必须让dx为负值,即文本的最左端,baseLine为正值。
- 绘制“步数”
这个相比于上一个就很简单了,上一步都已经计算出了所需绘制文字的左边位置以及底部基线。
这里应该可以看懂吧?dx/2,是由于“步数”只有两个字,大部分情况下是上面步数的1/2。而baseLine,你也只要计算出上个文字的baseLine+下面的文字高度就是“步数”的baseLine了。
使用
在布局中:
|
|
注意需要使用自定义名空间:xmlns:kevin="http://schemas.android.com/apk/res-auto"
Activity中,只需要调用暴露出来的方法,即可完成:
|
|
好了,这样就完成了步数运动这个自定义View了。