先看下最终的效果
开始实现
新建一个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软件编程有所帮助。