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

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

效果图:

基本原理,基本逻辑和其他时钟大同小异:定时器 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. angularJs上传文件(非form上传)

    angular.js:13920 Broken interceptor detected: Config object not supplied in rejection: <input typ ...

  2. TArray<uint8>转FString

    void ARamaUDPReceiver::Recv(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndP ...

  3. php 重写session

    重写session的存储机制 转自 http://www.cnblogs.com/bc8web/p/5699935.html Session数据区 默认以 文件的形式存储与服务器操作系统临时目录中! ...

  4. SQL Server中的SQL语句优化与效率

    很多人不知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解.比如: select * from table1 where name='zhan ...

  5. svn移动目录时如何保留原来的日志

    [问题描述] 想将SVN下的文件夹A移动目录D下,同时保留文件夹A及其下面文件的SVN日志 [原来的做法]         将文件夹A直接拷贝到目录D,然后提交到SVN [原来做法的问题]   日志无 ...

  6. 如何激励用户为你的app评分?

    如何激励用户为你的app评分? 2014-04-10 16:21 编辑: suiling 分类:营销推广 来源:CocoaChina  0 7247 应用设计应用评分 招聘信息: IOS兼职 深圳创业 ...

  7. Servlet------>jsp自定义标签3(不显示余下jsp内容)

    2.自定义标签控制,jsp页面余下标签是否继续执行 EndTag.java package tag; import javax.servlet.jsp.JspException; import jav ...

  8. 【Python算法】图与树的实现

    邻接列表及其类似结构 对于图结构的实现来说,最直观的方式之一就是使用邻接列表.下面我们来实现一个最简单的:假设现在我们有n个节点,编号分别为0,...,n-1. 然后,每个邻接列表就是一个数字列表,我 ...

  9. PHP Ajax跨域解决

    PHP Ajax 跨域问题最佳解决方案 本文通过设置Access-Control-Allow-Origin来实现跨域. 例如:客户端的域名是client.runoob.com,而请求的域名是serve ...

  10. 安装串口设备驱动时遇到 Windows 无法验证此设备所需的驱动程序的数字签名。最近的硬件或软件更改安装的文件可能未正确签名或已损坏,或者可能是来自未知来源的恶意软件. 问题该如何处理?

    win7 系统直接在 cmd 命令行中输入以下语句,重启电脑后重新安装驱动即可. BCDEDIT -SET LOADOPTIONS DISABLE_INTEGRITY_CHECKS BCDEDIT - ...