
[注意]转载时请注明出处博客园-吃唐僧肉的小悟空http://www.cnblogs.com/hukezhu/
今天使用CALayer的"定位点(锚点)"实现了一个时钟动画,其实就是一个小的时钟,只是实现了功能,没有做出绚丽的效果.使用UIView实现的,其实只是单纯的使用layer也可以实现.主要用到了 Quartz2D画图\ 事件处理\核心动画方面的知识.
代码不是很多,直接附上源码,注释比较详细,在源码后面再进行解释其中的一些知识点和注意点.
下图为应用截图,使用gif,没有制作好,见谅哈.[此处图片有一点小问题,时间显示正常,指针处有点问题,代码中修改过来了]


下图为模拟器与电脑时间对比图,和正常时间一样.

下面附上源代码:
viewController.m
这个是最初的源码,界面上没有显示数字时间的功能,把能够显示数字时间的源码放到最后面
1 //
2 // ViewController.m
3 // 01-时钟动画time
4 //
5 // Created by hukezhu on 15/6/12.
6 // Copyright (c) 2015年 hukezhu. All rights reserved.
7 //
8
9 #import "ViewController.h"
10
11 @interface ViewController ()
12 //秒针view
13 @PRoperty(nonatomic,strong)UIView *secondView;
14 //分针view
15 @property(nonatomic,strong)UIView *minView;
16 //时针view
17 @property(nonatomic,strong)UIView *hourView;
18 @end
19
20 @implementation ViewController
21
22 - (void)viewDidLoad {
23 [super viewDidLoad];
24 //设置背景颜色
25 self.view.backgroundColor = [UIColor greenColor];
26
27 //创建一个表盘view
28 UIView *clockView = [[UIView alloc]init];
29 //设置位置
30 clockView.center = self.view.center;
31 //设置大小
32 clockView.layer.bounds = CGRectMake(0, 0, 214, 214);
33
34 //设置显示内容
35 clockView.layer.contents = (__bridge id)([UIImage imageNamed:@"clock1"].CGImage);
36 //设置圆角半径
37 clockView.layer.cornerRadius = 107;
38 //设置裁剪
39 clockView.layer.masksToBounds = YES;
40 //将clockView添加到控制器view中
41 [self.view addSubview:clockView];
42
43
44
45
46 //创建一个秒针view
47 UIView *secondView = [[UIView alloc]init];
48 secondView.center = clockView.center;
49 secondView.layer.bounds = CGRectMake(0, 0, 2, 90);
50 secondView.layer.backgroundColor = [UIColor redColor].CGColor;
51 secondView.layer.anchorPoint = CGPointMake(0.5, 1);
52
53 self.secondView = secondView;
54 [self.view addSubview:secondView];
55
56
57
58 //创建一个分针view
59 UIView *minView = [[UIView alloc]init];
60 minView.center = clockView.center;
61 minView.layer.bounds = CGRectMake(0, 0, 4, 70);
62 minView.layer.backgroundColor = [UIColor blueColor].CGColor;
63 minView.layer.anchorPoint = CGPointMake(0.5, 1);
64
65 self.minView = minView;
66 [self.view addSubview:minView];
67
68
69
70 //创建一个时针view
71 UIView *hourView = [[UIView alloc]init];
72 hourView.center = clockView.center;
73 hourView.layer.bounds = CGRectMake(0, 0, 6, 50);
74 hourView.layer.backgroundColor = [UIColor blackColor].CGColor;
75 hourView.layer.anchorPoint = CGPointMake(0.5, 1);
76
77 self.hourView = hourView;
78 [self.view addSubview:hourView];
79
80
81 // 开启一个计时器控件
82 //NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(move) userInfo:nil repeats:YES];
83 //创建一个对象
84 CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(move)];
85 //启动这个link
86 [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
87 }
88
89
90 - (void)move{
91
92
93 //1.计算对应的弧度
94 CGFloat angle = M_PI * 2 / 60.0;
95 CGFloat angleMin = M_PI * 2 / 60.0;
96 CGFloat angleHour = M_PI * 2 / 12.0 ;
97
98 //2.获取当前事件
99 NSDate *date = [NSDate date];
100
101 //创建一个日历牌对象(NSCalender),通过这个对象才能获取NSDate中的日期时间的每一部分
102 NSCalendar *calender = [NSCalendar currentCalendar];
103
104 //告诉日历牌对象,需要获取哪些部分的值
105
106 //取得当前的秒
107 NSInteger secs = [calender component:NSCalendarUnitSecond fromDate:date];
108 //取得当前的分
109 NSInteger mins = [calender component:NSCalendarUnitMinute fromDate:date];
110 //取得当前的时
111 NSInteger hours = [calender component:NSCalendarUnitHour fromDate:date];
112
113
114 //NSLog(@"%zd,%zd,%zd",hours,mins,secs);//测试用
115
116
117 //计算本次旋转应该旋转到的弧度数
118 angle = secs *angle;
119 angleMin = mins *angleMin + angle/60.0;
120 angleHour = hours *angleHour + angleMin/12.0 ;
121
122 //让时分秒针旋转
123 self.secondView.transform = CGAffineTransformMakeRotation(angle);
124 self.minView.transform = CGAffineTransformMakeRotation(angleMin);
125 self.hourView.transform = CGAffineTransformMakeRotation(angleHour);
126
127 }
128
129 @end
当然,这里面的表盘使用的时图片,我们也可以自己画出来,但是此处有图片资源,就直接使用了.(注意需要剪切图片为圆形,当然,有方形的表盘,但是此处是圆形表盘,所以将图片切割成圆形).
注意:可以使用NSTimer创建一个定时器,但是通过 NSTimer 实现的动画可能造成卡顿、不连贯的情况(NSTimer 不准确),此处使用CADisplayLink.
主要思路就是:
获取当前系统中的时间的某一部分的方法
1 //2.获取当前事件 2 NSDate *date = [NSDate date]; 3 4 //创建一个日历牌对象(NSCalender),通过这个对象才能获取NSDate中的日期时间的每一部分 5 NSCalendar *calender = [NSCalendar currentCalendar]; 6 7 //告诉日历牌对象,需要获取哪些部分的值 8 9 //取得当前的秒 10 NSInteger secs = [calender component:NSCalendarUnitSecond fromDate:date]; 11 //取得当前的分 12 NSInteger mins = [calender component:NSCalendarUnitMinute fromDate:date]; 13 //取得当前的时 14 NSInteger hours = [calender component:NSCalendarUnitHour fromDate:date]; 15 16 17 //NSLog(@"%zd,%zd,%zd",hours,mins,secs);//测试用获取系统中的时间的某一部分的方法
知识点:
注意: 在使用 Quartz2D 绘图的时候, 对绘图上下文的旋转是对坐标系的旋转, 通过 UI 控件的 transform 对控件做旋转是按照 Center 来旋转的。
注意: 控件的 center 属性, 其实就是对应的 CALayer的 postion。所以控件的 center并不是永远表示控件的中心点。
UIView之所以能显示在屏幕上,完全是因为它内部的一个图层 在创建UIView对象时,UIView内部会自动创建一个图层(即CALayer对象),通过UIView的layer属性可以访问这个层 1 @property(nonatomic,readonly,retain) CALayer *layer; 当UIView需要显示到屏幕上时,会调用drawRect:方法进行绘图,并且会将所有内容绘制在自己的图层上,绘图完毕后,系统会将图层拷贝到屏幕上,于是就完成 了UIView的显示. CALayer的一些属性
//宽度和高度 @property CGRect bounds; //位置(默认指中点,具体由anchorPoint决定) @property CGPoint position; //锚点(x,y的范围都是0-1),决定了position的含义 @property CGPoint anchorPoint; //背景颜色(CGColorRef类型) @property CGColorRef backgroundColor; //形变属性 @property CATransform3D transform; //边框颜色(CGColorRef类型) @property CGColorRef borderColor; //边框宽度 @property CGFloat borderWidth; //圆角半径 @property CGFloat cornerRadius; //内容(比如设置为图片CGImageRef) @property(retain) id contents;
UIView和CALayer的使用区别:
UIView : 接受和处理系统事件、触摸事件。
CALayer : 显示内容
界面上有显示时间的label:(主要是一个定时器的功能,1秒刷新一次,显示在label上,实时动态的更新时间)
源码代码:
1 //
2 // ViewController.m
3 // 01-时钟动画time
4 //
5 // Created by hukezhu on 15/6/12.
6 // Copyright (c) 2015年 hukezhu. All rights reserved.
7 //
8
9 #import "ViewController.h"
10
11 @interface ViewController ()
12 //秒针view
13 @property(nonatomic,strong)UIView *secondView;
14 //分针view
15 @property(nonatomic,strong)UIView *minView;
16 //时针view
17 @property(nonatomic,strong)UIView *hourView;
18 //定时器
19 @property(nonatomic,strong)NSTimer *timer;
20 //显示时间的label
21 @property(nonatomic,strong)UILabel *timeLabel;
22 @end
23
24 @implementation ViewController
25
26 - (void)viewDidLoad {
27 [super viewDidLoad];
28 //设置背景颜色
29 self.view.backgroundColor = [UIColor greenColor];
30
31 //创建一个表盘view
32 UIView *clockView = [[UIView alloc]init];
33 //设置位置
34 clockView.center = self.view.center;
35 //设置大小
36 clockView.layer.bounds = CGRectMake(0, 0, 214, 214);
37
38 //设置显示内容
39 clockView.layer.contents = (__bridge id)([UIImage imageNamed:@"clock1"].CGImage);
40 //设置圆角半径
41 clockView.layer.cornerRadius = 107;
42 //设置裁剪
43 clockView.layer.masksToBounds = YES;
44 //将clockView添加到控制器view中
45 [self.view addSubview:clockView];
46
47
48 //创建一个显示时间的label
49 UILabel *label = [[UILabel alloc]init];
50
51 //设置位置
52 label.center = CGPointMake(clockView.center.x, clockView.center.y + 130);
53 //设置大小(这样设置不合理,代码很烂,只是单纯的为了实现这个小功能,也没有做自动布局)
54 label.frame = CGRectMake(clockView.center.x-60, clockView.center.y + 150, 100, 44);
55 //设置背景颜色
56 label.backgroundColor = [UIColor whiteColor];
57 //设置字体颜色
58 label.textColor = [UIColor redColor];
59 //设置字体居中
60 label.textAlignment = NSTextAlignmentCenter;
61 //设置字体大小
62 label.font = [UIFont systemFontOfSize:20];
63
64 self.timeLabel = label;
65 [self.view addSubview:label];
66
67
68
69
70
71 //创建一个秒针view
72 UIView *secondView = [[UIView alloc]init];
73 secondView.center = clockView.center;
74 secondView.layer.bounds = CGRectMake(0, 0, 2, 90);
75 secondView.layer.backgroundColor = [UIColor redColor].CGColor;
76 secondView.layer.anchorPoint = CGPointMake(0.5, 1);
77
78 self.secondView = secondView;
79 [self.view addSubview:secondView];
80
81
82
83 //创建一个分针view
84 UIView *minView = [[UIView alloc]init];
85 minView.center = clockView.center;
86 minView.layer.bounds = CGRectMake(0, 0, 4, 70);
87 minView.layer.backgroundColor = [UIColor blueColor].CGColor;
88 minView.layer.anchorPoint = CGPointMake(0.5, 1);
89
90 self.minView = minView;
91 [self.view addSubview:minView];
92
93
94
95 //创建一个时针view
96 UIView *hourView = [[UIView alloc]init];
97 hourView.center = clockView.center;
98 hourView.layer.bounds = CGRectMake(0, 0, 6, 50);
99 hourView.layer.backgroundColor = [UIColor blackColor].CGColor;
100 hourView.layer.anchorPoint = CGPointMake(0.5, 1);
101
102 self.hourView = hourView;
103 [self.view addSubview:hourView];
104
105
106 // 开启一个计时器控件
107 //NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(move) userInfo:nil repeats:YES];
108 //创建一个对象
109 CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(move)];
110 //启动这个link
111 [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
112
113
114 _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timeRun) userInfo:nil repeats:YES];
115 }
116
117 - (void)timeRun{
118
119 NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
120
121 [fmt setDateFormat:@" HH:mm:ss"];
122
123 NSString *time = [fmt stringFromDate:[NSDate date]];
124
125 [self.timeLabel setText:time];
126
127
128
129 }
130
131
132
133 - (void)move{
134
135
136 //1.计算对应的弧度
137 CGFloat angle = M_PI * 2 / 60.0;
138 CGFloat angleMin = M_PI * 2 / 60.0;
139 CGFloat angleHour = M_PI * 2 / 12.0 ;
140
141 //2.获取当前事件
142 NSDate *date = [NSDate date];
143
144 //创建一个日历牌对象(NSCalender),通过这个对象才能获取NSDate中的日期时间的每一部分
145 NSCalendar *calender = [NSCalendar currentCalendar];
146
147 //告诉日历牌对象,需要获取哪些部分的值
148
149 //取得当前的秒
150 NSInteger secs = [calender component:NSCalendarUnitSecond fromDate:date];
151 //取得当前的分
152 NSInteger mins = [calender component:NSCalendarUnitMinute fromDate:date];
153 //取得当前的时
154 NSInteger hours = [calender component:NSCalendarUnitHour fromDate:date];
155
156
157 //NSLog(@"%zd,%zd,%zd",hours,mins,secs);//测试用
158
159
160 //计算本次旋转应该旋转到的弧度数
161 angle = secs *angle;
162 angleMin = mins *angleMin + angle/60.0;
163 angleHour = hours *angleHour + angleMin/12.0 ;
164
165 //让时分秒针旋转
166 self.secondView.transform = CGAffineTransformMakeRotation(angle);
167 self.minView.transform = CGAffineTransformMakeRotation(angleMin);
168 self.hourView.transform = CGAffineTransformMakeRotation(angleHour);
169
170 }
171
172 @end
这段代码不是很规范,有许多需要优化的地方,只是单纯的实现了这个功能,请勿喷~~~~~~~~