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

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

效果图:

基本原理,基本逻辑和其他时钟大同小异:定时器 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. 简单配置Nginx 指向本地端口,并开启SSL

    简单配置Nginx 指向本地端口,并开启SSL,如果要开启SSL,必须使用域名去申请SSL key,一般是两个文件,一般是要收费的. # 在/etc/nginx/nginx.conf 的文件中有下面一 ...

  2. subprocess.Popen() 常用方法

    p.stdout.read() :用于读取标准输出,会一次性读取所有内容,返回一个字符串p.stdout.readline() :用于读取标准输出,一次只读取一行内容,返回一个字符串p.stdout. ...

  3. 主线程不能执行耗时的操作,子线程不能更新Ui

    在Android项目中经常有碰到这样的问题,在子线程中完成耗时操作之后要更新UI,下面就自己经历的一些项目总结一下更新的方法: 在看方法之前看一下Android中消息机制: 引用 Message:消息 ...

  4. RxJava的实现原理

    本周新的一天开始了,让我们一起造一个RxJava,揭秘RxJava的实现原理,  强烈推荐这个

  5. java 实现对指定目录的文件进行下载

    @RequestMapping("/exportDocument") @ResponseBody public void exportDocument(HttpServletReq ...

  6. Android 防破解技术简介

    Android 防破解技术简介 这几年随着互联网的不断发展,Android App 也越来越多!但是随之而来的问题也越来越多,这其中比较令人头疼的问题就是:有些不法分子利用反编译技术破解 App,修改 ...

  7. 《从零开始学Swift》学习笔记(Day 66)——Cocoa Touch设计模式及应用之通知机制

    原创文章,欢迎转载.转载请注明:关东升的博客 通知(Notification)机制是基于观察者(Observer)模式也叫发布/订阅(Publish/Subscribe)模式,是 MVC( 模型-视图 ...

  8. 160323、理解Java虚拟机体系结构

    今天看到一篇文章,觉得写得不错,特拿来跟大家分享一下 1 概述 众所周知,Java支持平台无关性.安全性和网络移动性.而Java平台由Java虚拟机和Java核心类所构成,它为纯Java程序提供了统一 ...

  9. R语言中基于聚类的离群点挖掘

    思路:首先,通过K-means算法将数据点划分为成若K个簇:然后计算每一个数据对象到最近簇的中心距离,来与离群点设置的阈值进行比较,以此来判别该数据对象是否是离群点. 1.读取数据 data<- ...

  10. 在VisualStudio 2013下使用VS2012的插件

    由于VS2013刚刚推出,而VS的插件又是和版本强相关的,因此VS2013就存在一个插件比较少的问题.虽然2013相对与2012来说改动并不大,应该是拿来重新编译一番就可以使用了.但也得有一个过程,并 ...