司机王教你用CALayer写一个iOS时钟效果
纯属原创,转载请标明出处,谢谢
首先我们先看一下需求
按照MAC的系统时钟仿照写一个类似的时钟效果
然后我们着手分析一个这个如何实现
首先这个不需要和用户有任何交互,所以我们推荐使用CALayer隐式动画去完成
然后我们让设计人员先画出一个表盘给我们,设置他的长宽都为200
其次,我们就要通过需求来描述CALayer的anchorPoint与position点在哪里
至于这两个点是什么(也就是“锚点”),彻底理解position与anchorPoint - yongyinmg的专栏 - 博客频道 - CSDN.NET,这篇文章说的很清楚了,这里就不跟大家解释
我们可以看到,所有的layer都是基于锚点去旋转的,也就是表盘的中心点,那么position属性也就是表盘的长宽的一半,由于anchorPoint的X,Y属性取值范围是0-1之间,以秒针举例,如果我们想让秒针站立在表盘中上,那么秒针的X即为0.5,Y为1
在设置下秒针的bound,宽度为1,长度为表盘的半径-20
这样我们可以轻松的将秒针针添加到表盘上
CALayer * secondL = [CALayer layer];
secondL.backgroundColor = [UIColor redColor].CGColor ;
// 设置锚点
secondL.anchorPoint = CGPointMake(0.5, 1);
secondL.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
secondL.bounds = CGRectMake(0, 0, 1, kClockW * 0.5 - 20);
[_clockView.layer addSublayer:secondL];
_secondLayer = secondL;
同理,时针和分针也是一样,只不过长度和颜色,圆角不一样
CALayer * layer = [CALayer layer];
layer.backgroundColor = [UIColor blackColor].CGColor ;
// 设置锚点
layer.anchorPoint = CGPointMake(0.5, 1);
layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 20);
layer.cornerRadius = 4;
[_clockView.layer addSublayer:layer];
_mintueLayer = layer;
CALayer * layer = [CALayer layer];
layer.backgroundColor = [UIColor blackColor].CGColor ;
// 设置锚点
layer.anchorPoint = CGPointMake(0.5, 1);
layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 40);
layer.cornerRadius = 4;
[_clockView.layer addSublayer:layer];
_hourLayer = layer;
这里一定要注意的是添加顺序,一般来讲秒针在最上层,所以秒针的layer是最后添加的
现在UI层我们已经添加好了,接下来就该考虑如何让时钟动起来了
让时钟动起来,我们先要知道时分秒他们在表盘上所谓转动的角度
通过小学运算可以得知,秒针在一秒钟内在表盘里转动的度数是6度(一个圆形是360度,360除以60),拿现在的系统的秒数*6就是现在秒针的具体度数
分针在一分钟内在表盘转动的度数也是6度
而时针呢,一小时时针变化为360除以12等于30度,但是有个问题,常理知,时钟并不是只有在分针转到12点的时候才变化,它表盘里也会随着分针的变化而变化(比如说1:30,时针不可能只还停留在1这个位置,等到2:00的时候才突然变化)所以这个角度还需要加上分针对它的变化。这个怎么算呢,拿30度除以60现在的系统分钟数就可以得到了,也就是0.5现在的分钟数就是时钟在以分钟作单位时转动的度数
30*系统小时+0.5*系统分钟
由于这些都是不可变化的,我们来抽成宏
// 1秒6度(秒针)
#define perSecondA 6
// 1分钟6度(分针)
#define perMintueA 6
// 1小时30度(时针)
#define perHourA 30
// 每分钟时针转(30 / 60 °)
#define perMinHourA 0.5
有了这些角度之后,剩下的就很好做了,我们在viewDidLoad的里添加一个定时器
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
然后在这个timeChange方法里,设置时分秒的旋转形变就可以了,这里注意,CATransform3DMakeRotation这个接受的弧度而不是角度,我们再抽出一个宏来将角度转化为弧度
#define angle2radion(angle) ((angle) / 180.0 * M_PI)
- (void)timeChange{
// 获取当前系统时间
NSCalendar * calender = [NSCalendar currentCalendar];
NSDateComponents * cmp = [calender components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour fromDate:[NSDate date]];
CGFloat second = cmp.second;
CGFloat secondA = (second * perSecondA) ;
NSInteger minute = cmp.minute;
CGFloat mintuteA = minute * perMintueA ;
NSInteger hour = cmp.hour;
CGFloat hourA = hour * perHourA + minute * perMinHourA;
_secondLayer.transform = CATransform3DMakeRotation(angle2radion(secondA), 0, 0, 1);
_mintueLayer.transform = CATransform3DMakeRotation(angle2radion(mintuteA), 0, 0, 1);
_hourLayer.transform = CATransform3DMakeRotation(angle2radion(hourA), 0, 0, 1);
}
做到这里,基本上已经大功告成,让我们运行一下
时钟已经随着系统时间转了起来,还可以在修改一些别的样式,到时候就看开发者如何发挥了
本Dome的Github地址
https://github.com/DriverWang/YCClock