最近本身 也尝试写了一个表盘时钟,初衷源于等车时候一个老奶奶问时间,我打开手机,时间数字对我来讲相对敏感,可是老奶奶是看不清的,我想识别 仍是看表盘 老远 看时针分针角度就能够识别当前时间。git
因而我想写一个表盘时钟。github
效果图:算法
基本原理,基本逻辑和其余时钟大同小异:定时器 repeat 获取当前时分秒,计算旋转角度,渲染UI。动画
几个注意的关键点,重点,难点。spa
一.旋转角度.net
以表盘为圆心,即 时针分针秒针绘制的矩形UI 锚点 anchorPoint. (默认锚点 是矩形中心点 anchorPoint(0.5,0.5)))code
//时钟偏转角度 CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0; //分钟偏转角度 CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0; //秒钟旋转角度 CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0; CGFloat prevSecAngle = ((components.second - 1) / 60.0) * M_PI * 2.0;
position 和 anchorPoint 关系:component
(1)position是layer中的anchorPoint在superLayer中的位置坐标。orm
(2)position与anchorPoint是处于不一样坐标空间中的重合点,修改重合点在一个坐标空间的位置不影响该重合点在另外一个坐标空间中的位置对象
(3)公式
frame.origin.x = position.x - anchorPoint.x * bounds.size.width;
frame.origin.y = position.y - anchorPoint.y * bounds.size.height;
二.秒针是否“扫秒或游走秒针”
每秒一动的秒针效果:
起初使用了
self.secondHandImageV.transform = CGAffineTransformMakeRotation(secsAngle);
游走秒针使用:
//提早存储秒针layer的初始位置 [self.secondHandImageV.layer removeAnimationForKey:@"transform"]; CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"transform"]; ani.duration = 1.f; ani .removedOnCompletion= NO; //ani.delegate = self; ani.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(prevSecAngle , 0, 0, 1)]; ani.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(secsAngle , 0, 0, 1)]; [self.secondHandImageV.layer addAnimation:ani forKey:@"transform"];
由于一个事layer层的变化 一个不是,当两种秒针效果在真机中切换的时候 总会闪动 缘由参见参考2
因而须要及时修改layer层的联动变化添加了
ani.delegate = self; #pragma mark -CAAnimationDelegate - (void)animationDidStart:(CAAnimation *)anim { //防止layer动画闪动 self.secondHandImageV.layer.transform = CATransform3DMakeRotation (self.secondAngel, 0, 0, 1); //NSLog(@"animationDidStart%@",self.secondHandImageV.layer.animationKeys); } - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ //防止layer动画闪动 self.secondHandImageV.layer.transform = CATransform3DMakeRotation (self.secondAngel, 0, 0, 1); //NSLog(@"animationDidStop%@",self.secondHandImageV.layer.animationKeys); }
三.时针分针动一下时候de效果
期初都是知足条件 1秒直接跳到下一个位置,可是在“扫描/游走秒针”效果下,仿佛临界的跳动状态不具备一致性,因而在“扫描/游走秒针”状态下,时针 分针 添加一个1s de animation. 总体临界效果就天然了
总体timer 定时任务以下:
#pragma mark -- 定时任务 - (void)tick { // NSCalendarIdentifierGregorian : 指定日历的算法 NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; // NSDateComponents封装了日期的组件,年月日时分秒等(我的感受像是平时用的model模型) // 调用NSCalendar的components:fromDate:方法返回一个NSDateComponents对象 // 须要的参数分别components:所须要的日期单位 date:目标月份的date对象 // NSUInteger units = NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;//所须要日期单位 NSDateComponents *components = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:[NSDate date]]; //时钟偏转角度 CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0; //分钟偏转角度 CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0; //秒钟旋转角度 CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0; CGFloat prevSecAngle = ((components.second - 1) / 60.0) * M_PI * 2.0; self.secondAngel = secsAngle ; if (self.isWanderSecond) { //提早存储秒针layer的初始位置 [self.secondHandImageV.layer removeAnimationForKey:@"transform"]; CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"transform"]; ani.duration = 1.f; ani .removedOnCompletion= NO; ani.delegate = self; ani.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(prevSecAngle , 0, 0, 1)]; ani.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeRotation(secsAngle , 0, 0, 1)]; [self.secondHandImageV.layer addAnimation:ani forKey:@"transform"]; } else { [self.secondHandImageV.layer removeAnimationForKey:@"transform"]; self.secondHandImageV.layer.transform = CATransform3DMakeRotation (secsAngle, 0, 0, 1); //self.secondHandImageV.transform = CGAffineTransformMakeRotation(secsAngle); } // if (self.isWanderSecond && self.isContinuous) { [UIView animateWithDuration:1.0 animations:^{ self.hourHandImageV.transform = CGAffineTransformMakeRotation(hoursAngle); self.minuteHandImageV.transform = CGAffineTransformMakeRotation(minsAngle); }]; } else { self.isContinuous = YES; self.hourHandImageV.transform = CGAffineTransformMakeRotation(hoursAngle); self.minuteHandImageV.transform = CGAffineTransformMakeRotation(minsAngle); } }
github地址 TimeClock
参考
1.https://www.jianshu.com/p/2f8962055f21 (layer层 中 position 和 anchorPoint 关系)
2. https://blog.csdn.net/mydo/article/details/51553982