最近自己 也尝试写了一个表盘时钟,初衷源于等车时候一个老奶奶问时间,我打开手机,时间数字对我来说相对敏感,但是老奶奶是看不清的,我想识别 还是看表盘 老远 看时针分针角度就可以识别当前时间。

于是我想写一个表盘时钟。

效果图:

基本原理,基本逻辑和其他时钟大同小异:定时器 repeat 获取当前时分秒,计算旋转角度,渲染UI。

几个注意的关键点,重点,难点。

一.旋转角度

以表盘为圆心,即 时针分针秒针绘制的矩形UI 锚点 anchorPoint. (默认锚点 是矩形中心点 anchorPoint(0.5,0.5)))

    //时钟偏转角度
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 关系:

(1)position是layer中的anchorPoint在superLayer中的位置坐标。

(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

iOS 绘制一个表盘时钟,秒针效果可以“扫秒/游走”的更多相关文章

  1. 用canvas绘制一个简易时钟

    在见识了html5中canvas的强大,笔者准备制作一个简易时钟. 下面就是成果啦,制作之前我们先分析一下,绘制一个时钟需要做哪些准备. 一 . 1.首先这个时钟分为表盘,指针(时针,分针,秒针)和数 ...

  2. 转:iOS绘制一个UIView

    绘制一个UIView 绘制一个UIVIew最灵活的方式就是由它自己完成绘制.实际上你不是绘制一个UIView,你只是子类化了UIView并赋予子类绘制自己的能力.当一个UIVIew需要执行绘图操作的时 ...

  3. IOS中一个简单的粒子效果实现

    1.效果图展示 2.实现思路 1> 首先要实现上面的效果,第一步要处理的就是一个简单的画板,在View上面用鼠标滑动的时候画出线条,这个功能可使用UIBezierPath实现 2> 关于粒 ...

  4. 使用canvas绘制一个时钟

    周末学习canvas的一些基础功能,顺带写了一个基础的时钟.现在加工一下,做的更好看一点,先放上效果图: 谈一些自己的理解: (1).要绘制一个新的样式(不想被其他样式影响,或者影响到其他样式),那么 ...

  5. iOS时钟,秒针扫秒样式

    昨天做一个时钟小demo,发现了一些问题. 描述能力有限,我封装好了一个时钟框架,朋友们可以参考      https://github.com/qianlishun/ClockView 点击这里可以 ...

  6. IOS 中openGL使用教程2(openGL ES 入门篇 | 绘制一个多边形)

    在上一篇我们学习了如何搭建IOS下openGL的开发环境,接下来我们来学习如何绘制一个多边形. 在2.0之前,es的渲染采用的是固定管线,何为固定管线,就是一套固定的模板流程,局部坐标变换 -> ...

  7. 利用canvas画一个实时时钟

    先放一张效果图: 下面是源代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...

  8. iOS----自定义UIView,绘制一个UIView

    绘制一个UIVIew最灵活的方式就是由它自己完成绘制.实际上你不是绘制一个UIView,你只是子类化了UIView并赋予子类绘制自己的能力.当一个UIVIew需要执行绘图操作的时,drawRect:方 ...

  9. 高仿IOS下拉刷新的粘虫效果

    最近看需要做一款下拉刷新的效果,由于需要和Ios界面保持一致,所以这用安卓的方式实现了ios下的下拉刷新的粘虫效果. 最新的安卓手机版本的QQ也有这种类似的效果,就是拖动未读信息的那个红色圆圈,拖动近 ...

随机推荐

  1. 数据库unsigned char*类型图片存进

    loadimage1();测试: void Caccess_test_1Dlg::loadimage1()//存入unsigned char*类型的数据图片 { CFileException e; I ...

  2. ios 从URL中截取所包含的参数,并且以字典的形式返回和参数字典转URL

    //字典转链接(参数) - (NSString *)keyValueStringWithDict:(NSDictionary *)dict { if (dict == nil) { return ni ...

  3. MyEclipse------如何添加jspsmartupload.jar,用于文件上传

    方法: 右键“Web”工程->properties->Libraries->Add External JARs...->找到“jspsmartupload.jar”,添加进去 ...

  4. asp 中创建日志打印文件夹

    string FilePath = HttpRuntime.BinDirectory.ToString(); string FileName = FilePath + "日志" + ...

  5. LeetCode 笔记系列 18 Maximal Rectangle [学以致用]

    题目: Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones ...

  6. java面向对象基础回顾

    (49)  (0) 面向对象 啥是面向对象 什么是多态多态的机制 接口和抽象类区别 个人理解 代码实现 面向对象 学习java大家接触到的最多的话语无非就是面向对象,可能大家没有仔细研究过这个问题,但 ...

  7. 谨防in、or 公用性能问题

    今天遇到一个奇葩的问题:在where条件中用了 m in(×××) or m>=10,查询直接超时,我看了一下,数据库中就2万条数据 我将查询改为了union all 结果就不超时了

  8. nginx分发请求的2种方式:1、指明server_name;2、通过location过滤uri来分发请求;

    user nginx; worker_processes 8; # = cpu num; error_log /data/nginx/log/error/error.log warn; # warn, ...

  9. Storm-源码分析-Topology Submit-Task-TopologyContext (backtype.storm.task)

    1. GeneralTopologyContext 记录了Topology的基本信息, 包含StormTopology, StormConf 已经从他们推导出的, task和component, co ...

  10. 前端开发 - HTML

    1.index2.head标签相关内容3.常用标签一4.常用标签二 table5.常用标签二 form6.标签分类 1.index <!--声明文档的类型 标记该文档为HTML5的文件--> ...