实现原理分析
- 刻度线绘制:画一个刻度线很简单,就是canvas.drawLine,但是根据角度每30度绘制一个刻度线怎么实现呢,我们一开始想到的可能会是根据角度,利用三角函数等去计算每个刻度线的开始坐标和结束坐标,但这种方式未免过于复杂,稍有不慎就会计算错误。但是利用画布的旋转canvas.rotate就会非常的简单,刻度线只需按照12点钟方向绘制即可,每次绘制完一个刻度线,画布旋转30度,再按照12点钟方向绘制即可。
- 指针绘制:同样也是通过canvas.drawLine绘制3个指针,为paint设置不同的属性实现时针,分针,秒针的显示样式,同理,如果我们根据角度去计算指针的坐标,那就很复杂,这里也是通过画布的旋转,那么旋转的角度怎么确定呢,就是根据当前时间去确定(具体算法后面代码中具体分析)。
- 动态:为了实现时钟的动态转动,我们需要在onDraw中每一秒钟获取一次当前时间,然后计算3个指针的旋转角度,再绘制就行了。
这样一分析,其实自定义时钟很简单,就是绘制圆,然后通过画布的旋转绘制刻度线和指针。
具体实现过程
绘制圆
//绘制圆 canvas.drawCircle(centerX, centerY, radius, circlePaint);
其中centerX和centerY为圆心,用当前控件的中心点即可,radius为圆的半径,采用当前控件宽高的最小值/2 即可,或者自行设置。
绘制刻度线
12个刻度线,循环12次,每3个刻度线就是一刻钟的刻度线,可以设置不同的样式区分。然后根据12点钟方向绘制刻度线。
开始x坐标:圆心x坐标;
开始y坐标:圆心y坐标-半径+间隙;
结束x坐标:圆心x坐标;
结束y坐标:开始y坐标+刻度线长度;
每绘制完一个刻度线后,画布就在之前的基础上旋转30度,继续绘制12点钟刻度线,这样,刻度线就基于旋转后的画布绘制,也就是斜着绘制了刻度线,很方便的实现了刻度线的绘制。
这里给出主要的绘制代码,全部代码后面贴出
//刻度线长度 private final static int MARK_LENGTH = 20; //刻度线与圆的间隙 private final static int MARK_GAP = 12; //绘制刻度线 for (int i = 0; i < 12; i++) { if (i % 3 == 0) {//一刻钟 markPaint.setColor(mQuarterMarkColor); } else { markPaint.setColor(mMinuteMarkColor); } canvas.drawLine( centerX, centerY - radius + MARK_GAP, centerX, centerY - radius + MARK_GAP + MARK_LENGTH, markPaint); canvas.rotate(30, centerX, centerY); } canvas.save();
绘制指针
绘制时针,分针,秒针,我们分别用3个canvas去绘制,最后再将这3个画布的bitmap绘制到控件的canvas中,为的是单独控制每个画布的旋转角度。
首先分析时针的指针角度,钟一圈是12个小时,360度,那么每小时就是30度,假设当前时间的小时是h(12小时制),那么时针的旋转角度就是h*30,同刻度线一样,我们也不去计算该角度的指针的各种坐标,而是直接将时针的画布旋转h*30度,然后绘制12点钟方向的时针就行了。
接着是分针角度,钟一圈是60分钟,360度,那么每分钟就是6度,假设当前时间的分钟是m,那么分针的旋转角度就是m*6
最后是秒针角度,钟一圈是60秒,360度,那么每秒就是6度,假设当前时间的秒数是s,那么秒针的旋转角度就是s*6
分析完了时针,分针,秒针的角度获取,那么之后就很简单了,在onDraw中,我们每过一秒获取一次当前时间的时分秒,按照上面的算法计算角度,然后旋转相应的画布,之后绘制相应的指针(当然要注意画布的清空和还原),那么一个随着时间的流逝而旋转的时钟就出来了。
这里给出绘制时针的主要代码&#