先看下最终的效果
开始实现
新建一个clockview集成view
1
2
3
|
public class clockview extends view { } |
先重写onmeasure方法,这里要先说一下view的测量模式,一共有三种:
1、exactly
即精确值模式,当我们将控件的layout_width属性或layout_height属性指定为具体数值时,比如android:layout_width="100dp",或者指定为math_parent属性时(占据父view的大小),系统使用的是exactly模式。
2、at_most
即最大值模式,当控件的layout_width属性或layout_height属性指定为wrap_content时,控件大小一般随着控件的子控件或内容的变化而变化,此时控件的尺寸只要不超过父控件允许的最大尺寸即可。
3、unspecified
这个属性比较奇怪——它不指定其大小测量模式,view想多大就多大,通常情况下在绘制自定义view时才会使用。
因为view的onmeasure方法只支持exactly模式,当layout_width和layout_height为wrap_content时,view的大小就显得很奇怪了,如下图。
所以我们重写一下onmeasure方法可以指定view width、height的最小值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/** * 当布局为wrap_content时设置默认长宽 * @param widthmeasurespec * @param heightmeasurespec */ @override protected void onmeasure( int widthmeasurespec, int heightmeasurespec) { setmeasureddimension(measure(widthmeasurespec), measure(heightmeasurespec)); } private int measure( int origin){ int result = default_min_width; int specmode = measurespec.getmode(origin); int specsize = measurespec.getsize(origin); if (specmode == measurespec.exactly){ result = specsize; } else { if (specmode == measurespec.at_most){ result = math.min(result, specsize); } } return result; } |
下面就是最重要的重写ondraw方法来绘制表盘、刻度、指针……,大致流程如下
1、画表盘,用drawcircle绘制一个圆作为表盘, 圆心坐标为(getwidth()/2, getheight()/2),半径为math.min(getheight()/2, getwidth()/2)。
1
2
3
4
5
6
7
|
//画外圆 float borderwidth = default_border_width; paint paintcircle = new paint(); paintcircle.setstyle(paint.style.stroke); paintcircle.setantialias( true ); paintcircle.setstrokewidth(borderwidth); canvas.drawcircle(getwidth() / 2 , getheight() / 2 , math.min(getheight() / 2 , getwidth() / 2 ) - borderwidth / 2 , paintcircle); |
2、画刻度线,在这里我们可以利用一个`canvas.rotate'方法就可以不用计算角度了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//画刻度线 float degreelength = 0f; paint paintdegree = new paint(); paintdegree.setantialias( true ); for ( int i= 0 ;i< 60 ;i++){ if (i % 5 == 0 ){ paintdegree.setstrokewidth( 6 ); degreelength = default_long_degree_length; } else { paintdegree.setstrokewidth( 3 ); degreelength = default_short_degree_length; } canvas.drawline(getwidth()/ 2 , math.abs(getwidth()/ 2 - getheight()/ 2 ), getwidth()/ 2 , math.abs(getwidth()/ 2 - getheight()/ 2 ) + degreelength, paintdegree); canvas.rotate( 360 / 60 , getwidth()/ 2 , getheight()/ 2 ); } |
3、画刻度上的数字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//刻度数字 int degressnumbersize = 30 ; canvas.translate(getwidth() / 2 , getheight() / 2 ); paint paintdegreenumber = new paint(); paintdegreenumber.settextalign(paint.align.center); paintdegreenumber.settextsize(degressnumbersize); paintdegreenumber.setfakeboldtext( true ); for ( int i= 0 ;i< 12 ;i++){ float [] temp = calculatepoint((i+ 1 )* 30 , r - default_long_degree_length - degressnumbersize/ 2 - 15 ); canvas.drawtext((i+ 1 )+ "" , temp[ 2 ], temp[ 3 ] + degressnumbersize/ 2 - 6 , paintdegreenumber); } /** * 根据角度和长度计算线段的起点和终点的坐标 * @param angle * @param length * @return */ private float [] calculatepoint( float angle, float length){ float [] points = new float [ 4 ]; if (angle <= 90f){ points[ 0 ] = -( float ) math.sin(angle*math.pi/ 180 ) * default_point_back_length; points[ 1 ] = ( float ) math.cos(angle*math.pi/ 180 ) * default_point_back_length; points[ 2 ] = ( float ) math.sin(angle*math.pi/ 180 ) * length; points[ 3 ] = -( float ) math.cos(angle*math.pi/ 180 ) * length; } else if (angle <= 180f){ points[ 0 ] = -( float ) math.cos((angle- 90 )*math.pi/ 180 ) * default_point_back_length; points[ 1 ] = -( float ) math.sin((angle- 90 )*math.pi/ 180 ) * default_point_back_length; points[ 2 ] = ( float ) math.cos((angle- 90 )*math.pi/ 180 ) * length; points[ 3 ] = ( float ) math.sin((angle- 90 )*math.pi/ 180 ) * length; } else if (angle <= 270f){ points[ 0 ] = ( float ) math.sin((angle- 180 )*math.pi/ 180 ) * default_point_back_length; points[ 1 ] = -( float ) math.cos((angle- 180 )*math.pi/ 180 ) * default_point_back_length; points[ 2 ] = -( float ) math.sin((angle- 180 )*math.pi/ 180 ) * length; points[ 3 ] = ( float ) math.cos((angle- 180 )*math.pi/ 180 ) * length; } else if (angle <= 360f){ points[ 0 ] = ( float ) math.cos((angle- 270 )*math.pi/ 180 ) * default_point_back_length; points[ 1 ] = ( float ) math.sin((angle- 270 )*math.pi/ 180 ) * default_point_back_length; points[ 2 ] = -( float ) math.cos((angle- 270 )*math.pi/ 180 ) * length; points[ 3 ] = -( float ) math.sin((angle- 270 )*math.pi/ 180 ) * length; } return points; } |
4、画指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//画指针 paint painthour = new paint(); painthour.setantialias( true ); painthour.setstrokewidth( 15 ); paint paintminute = new paint(); paintminute.setantialias( true ); paintminute.setstrokewidth( 10 ); paint paintsecond = new paint(); paintsecond.setantialias( true ); paintsecond.setstrokewidth( 5 ); calendar now = calendar.getinstance(); float [] hourpoints = calculatepoint(now.get(calendar.hour_of_day)% 12 /12f* 360 , hourpointerlength); canvas.drawline(hourpoints[ 0 ], hourpoints[ 1 ], hourpoints[ 2 ], hourpoints[ 3 ], painthour); float [] minutepoints = calculatepoint(now.get(calendar.minute)/60f* 360 , minutepointerlength); canvas.drawline(minutepoints[ 0 ], minutepoints[ 1 ], minutepoints[ 2 ], minutepoints[ 3 ], paintminute); float [] secondpoints = calculatepoint(now.get(calendar.second)/60f* 360 , secondpointerlength); canvas.drawline(secondpoints[ 0 ], secondpoints[ 1 ], secondpoints[ 2 ], secondpoints[ 3 ], paintsecond); |
5、画圆心
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
//画圆心 paint paintcenter = new paint(); paintcenter.setcolor(color.white); canvas.drawcircle( 0 , 0 , 2 , paintcenter); 最后只要启动一个无限循环的线程,每隔 1 秒针重绘一下view就能让指针动起来了 private thread timethread = new thread() { @override public void run() { try { while ( true ){ updatehandler.sendemptymessage( 0 ); thread.sleep( 1000 ); } } catch (interruptedexception e) { e.printstacktrace(); } } }; private handler updatehandler = new handler() { @override public void handlemessage(message msg) { invalidate(); } }; |
以上就是教大家如何利用android画个时钟的详细步骤代码,希望对大家的学习android软件编程有所帮助。