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

基本原理,基本逻辑和其他时钟大同小异:定时器 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 绘制一个表盘时钟,秒针效果可以“扫秒/游走”的更多相关文章
- 用canvas绘制一个简易时钟
在见识了html5中canvas的强大,笔者准备制作一个简易时钟. 下面就是成果啦,制作之前我们先分析一下,绘制一个时钟需要做哪些准备. 一 . 1.首先这个时钟分为表盘,指针(时针,分针,秒针)和数 ...
- 转:iOS绘制一个UIView
绘制一个UIView 绘制一个UIVIew最灵活的方式就是由它自己完成绘制.实际上你不是绘制一个UIView,你只是子类化了UIView并赋予子类绘制自己的能力.当一个UIVIew需要执行绘图操作的时 ...
- IOS中一个简单的粒子效果实现
1.效果图展示 2.实现思路 1> 首先要实现上面的效果,第一步要处理的就是一个简单的画板,在View上面用鼠标滑动的时候画出线条,这个功能可使用UIBezierPath实现 2> 关于粒 ...
- 使用canvas绘制一个时钟
周末学习canvas的一些基础功能,顺带写了一个基础的时钟.现在加工一下,做的更好看一点,先放上效果图: 谈一些自己的理解: (1).要绘制一个新的样式(不想被其他样式影响,或者影响到其他样式),那么 ...
- iOS时钟,秒针扫秒样式
昨天做一个时钟小demo,发现了一些问题. 描述能力有限,我封装好了一个时钟框架,朋友们可以参考 https://github.com/qianlishun/ClockView 点击这里可以 ...
- IOS 中openGL使用教程2(openGL ES 入门篇 | 绘制一个多边形)
在上一篇我们学习了如何搭建IOS下openGL的开发环境,接下来我们来学习如何绘制一个多边形. 在2.0之前,es的渲染采用的是固定管线,何为固定管线,就是一套固定的模板流程,局部坐标变换 -> ...
- 利用canvas画一个实时时钟
先放一张效果图: 下面是源代码: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"& ...
- iOS----自定义UIView,绘制一个UIView
绘制一个UIVIew最灵活的方式就是由它自己完成绘制.实际上你不是绘制一个UIView,你只是子类化了UIView并赋予子类绘制自己的能力.当一个UIVIew需要执行绘图操作的时,drawRect:方 ...
- 高仿IOS下拉刷新的粘虫效果
最近看需要做一款下拉刷新的效果,由于需要和Ios界面保持一致,所以这用安卓的方式实现了ios下的下拉刷新的粘虫效果. 最新的安卓手机版本的QQ也有这种类似的效果,就是拖动未读信息的那个红色圆圈,拖动近 ...
随机推荐
- 在Chem 3D软件用什么方法可以改变背景
化学绘图过程中常常需要绘制三维结构的图形,Chem 3D软件是ChemOffice套件中专门用于绘制三维结构的组件.用过它的用户会发现,其背景颜色通常都默认为深蓝色,但是不是每个场景都适合用深蓝色的背 ...
- HTML 标签 参考手册
按功能类别排列 基础 标签 描述 <!DOCTYPE> 定义文档类型. <html> 定义 HTML 文档. <title> 定义文档的标题. <body& ...
- 说说M451例程之PWM的寄存器讲解
M451提供了两路PWM发生器.每路PWM支持6通道PWM输出或输入捕捉.有一个12位的预分频器把时钟源分频后输入给16位的计数器,另外还有一个16位的比较器.PWM计数器支持向上,向下,上下计数方式 ...
- IOS 预览word文档的集中方式
在iPhone中可以很方便的预览文档文件,如:pdf.word等等,这篇文章将以PDF为例.介绍三种预览PDF的方式,又分别从本地pdf文档和网络上的pdf文档进行对比. 预览本地PDF文档: 1.使 ...
- maven仓库加载本地包依赖
如果有个jar包是我们自己打的,怎么放到maven中呢? 首先在项目里面新建一个lib目录,如果有lib目录则不需要新建,然后放自己的jar包进去,maven的pom.xml配置是: <depe ...
- Python巨蟒全栈开发目录
巨蟒python全栈开发-第一阶段 基础数据类型&基础 1.什么是计算机&&python的简介(待补充) 2.while循环&&格式化输出&&运 ...
- 巨蟒python全栈开发flask14项目开始6
1.App未读消息显示 2.发起好友请求 3.同意拒绝好友请求 4.玩具社交圈 1.App未读消息显示 2.发起好友请求 3.同意拒绝好友请求 4.玩具社交圈
- Spoken English Practice(Don't get me wrong, that explanation makes no difference, I'm still mad at you. Come on, be reasonable!)
绿色:连读: 红色:略读: 蓝色:浊化: 橙色:弱读 下划线_为浊化 口语蜕变(2017/7/11) ...
- CORBA(Common Object Request Broker Architecture,公共对象请求代理体系结构,通用对象请求代理体系结构)是由OMG组织制订的一种标准的面向对象应用程序体系规范
CORBA(Common Object Request Broker Architecture,公共对象请求代理体系结构,通用对象请求代理体系结构)是由OMG组织制订的一种标准的面向对象应用程序体系规 ...
- LeetCode_Search in Rotated Sorted Array
题目: Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 ...