ios开发-UI进阶-核心动画-时钟动画小案例
[注意]转载时请注明出处博客园-吃唐僧肉的小悟空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.
主要思路就是:
- 设置view的背景
- 创建一个表示表盘的view,设置表盘view的大小和位置,在contents属性中设置图片,根据圆角半径的知识,使用masksToBounds进行剪切,将这个view加到控制器的view中
- 分别创建一个秒针\分针\时针的view,分别设置大小和位置,设置颜色,等属性,分别将view加入到控制器的view中.
- 创建一个CADisplayLink对象,(CADisplayLink能提供一个周期性调用赋值给它的selector的机制,很像定时器NSTimer)
- 实现上述CADisplayLink对象中添加的move方法
- 在move方法中,计算所转的弧度,通过日历牌对象(NSCalender),获取NSDate中的日期时间的每一部分
- 进行旋转,完毕!
获取当前系统中的时间的某一部分的方法
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并不是永远表示控件的中心点。
CALayer有2个非常重要的属性:position和anchorPoint
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 : 接受和处理系统事件、触摸事件。
界面上有显示时间的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
这段代码不是很规范,有许多需要优化的地方,只是单纯的实现了这个功能,请勿喷~~~~~~~~