iOS开发之动画中的时间(概况)
一、引言
在iOS开发中使用动画时,可以通过设置动画的duration
、speed
、begintime
、offset
属性,来设置动画的时长、速度、起始时间及起始偏移。
用一个简单的例子来说明各个参数的的作用。动画很简单,一个红色的方块从左移到右边。动画的持续时间是1s,没有重复,效果如下。
CFTimeInterval currentTime = CACurrentMediaTime();
CFTimeInterval currentTimeInLayer = [self.testLayer convertTime:currentTime fromLayer:nil];
CFTimeInterval addTime = currentTimeInLayer;
anim.beginTime = 0.3 + addTime;
[anim setTimeOffset:0.5];
[anim setSpeed:2];
做修改以后,效果如下:
与上面相比,三处不同
- 动画的速度是原来的两倍。
- 点击开始动画的按钮,到开始动画,有一个延迟。
- 动画起始时,滑块的位置为中央,而不是在左边。
我们已经看到了这些属性的效果。翻阅文档,发现begintime
、speed
等属性是CAMediaTiming
这协议的属性,并且CALayer
、CAAnimation
都遵守了CAMediaTiming
协议。
那么CAMediaTiming
协议是什么呢?有什么作用呢?
二、层级时间结构
根据文档,CMediaTiming
协议构建了一个层级的时间系统,并用这个层级的时间系统来协调各个layer、animation的时间。
这个协议被CAAnimation
及CALayer
遵守,每一个遵守协议的的object对应一个time space
。根据object之间的关系,不同的time space
有层级关系。比如Layer A有一个subLayer B,那么Layer A对应的time space
就是layer B对应的time space
的parent time space
。每一个time space
中时间的数值都是根据parent time space
的数值,以及begintime
、speed
等属性,根据一定的规则来计算的。
为了便于理解层级时间系统,先看下layer在屏幕上的显示位置是如何确定的,然后做一个类比。
layer层级如上。要确定sublayer1在屏幕上的显示位置,一共分三步。
- 确定window layer在屏幕位置position1
- 根据position1及view layer的position属性,确定view layer在屏幕中的位置position2
- 根据position2及sublayer1的position属性,确定sublayer1在屏幕中的位置position3
与此类似,要确定sub1ayer1中的time,也要分三步。
- 确定window layer中的time1
- 根据time1及view layer的
begintime
、offset
等属性计算出view layer中的time2 - 根据time2及sublayer1的
begintime
、offset
等属性计算出sublayer中的time3
和确定layer的位置相比,确定时间有一些复杂,主要提现在下面两点
- 层级时间系统的构成复杂。
layer tree的每一级都是CALayer,而只要遵守CAMediaTiming
协议,就可以作为层级时间系统的一部分。比如CALayer
、CAAnimation
(及其子类CAAnimationGroup
)都可以作为层级时间系统的一部分。 - 不同层级之间时间转换规则复杂
计算当前layer的位置时,只需要知道父layer的位置,以及当前layer的position属性。计算当前层级时间时,不仅需要知道上一个层级的时间,还需要知道当前层级的begintime
、offset
、speed
等属性。转换的规则也比较复杂,要经历两次转换。从parent time
到active local time
,再到basic local time
。
三、active local time
这次转换是为了处理当前层级的object在父层级的的时间线上的位置,以及当前层级和父层级之间时间流逝速度的关系。
和这次转换相关的属性有beginTime
、speed
以及timeOffset
begin time
子层级相对于父层级的起始时间。也就是父层级的时间经过多久,子层级才开始计算时间。
比如子层级A被加入层级时间系统时,它父层级B的时间是5s,子层级A的begintime
是6s,那么当它父层级的时间变为6s时,子层级才开始计算时间。speed
子层级相对于父层级的时间流逝速度。如果speed是2,那么当父层级的时间增加了10s时,子层级的时间增加了20s(10s的2倍)。timeOffset
为本地时间增加一个偏移。 如果timeOffset
是5s,那么本地时间的起始就是5s。
从parent time
到active local time
有一个公式,可以用来参考。
t = (tp - begin) * speed + offset
四、basic local time
这次转换是为了处理当前层级的重放(repeat)、以及重放之前是否要倒放(play backward)等操作。
比如当前层级是一个动画(CAAnimation
遵守CAMediaTiming
协议),duration
是1s,经过第一次转换之后的active local time
是5.5s。如果动画的repeatCount
是10,那么经过第二次转化以后,basic local time
会是0.5s,因此当前是动画展示一半的状态。
repeatCount
及repeatDuration
当前的层级要重复的次数或重复的时间,两者不可同时指定。
以动画为例,如果指定repeatCount
,那么指定了动画要重复几次。如果指定了repeatDuration
,那么指定了动画重复的时间。autoreverses
在重复之前是否要倒放。
五、文首的例子
根据这些知识,可以解释文章开始时设置参数的效果。
当动画被加到layer上时,动画对应的time space
被加到层级时间系统中,是layer对应的time space
的子层级。
- 动画的速度是原来的两倍
设置动画的speed
是2,这样子动画中的时间流逝速度时layer中时间流逝速度的2倍。当layer中时间经过0.5s时,动画中时间已经流逝了1s,动画已经完成了。(动画的duration
是1s) - 点击开始动画的按钮,到开始动画,有一个延迟
我们首先得到了当前layer的时间addtime
,然后把动画的begintime
设置为addtime+0.3
。这样子当动画被加到layer之后0.3s,layer中的时间是addtime+0.3
,此时动画中的时间才开始计算,之前动画没有开始。 - 动画起始时,滑块的位置为中央,而不是在左边
我们设置了动画的offset
为0.5s。当动画开始时,动画对应的time space
的时间是0.5s,对应动画duration
的一半,即滑块位置在屏幕中央。
六、更多应用
了解了CAMediaTiming
协议后,可以实现很多动画的效果。
- 让某一个layer上的动画停止
设置layer的speed
为0即可。 - 实现门打开然后关闭的效果
实现一个门打开的动画,然后把动画的autoreverses
属性设置为YES
即可。 - layer上的若干动画依次延迟启动
分别设置这些动画的beginTime
为不同的值即可 - 手动控制动画的进度
设置动画的speed
为0,然后改变动画的offset
即可。
苹果已经把工具给我们了,可以做出什么样的产品就看大家的想象力了。
参考
控制动画时间
控制动画时间(上文的中文版)
Time Warp in Animation
iOS开发之动画中的时间(概况)的更多相关文章
- iOS开发之动画中的时间
概述 在动画中,我们会指定动画的持续时间.例如 scaleAnimation.duration = self.config.appearDuration 那么这个时间是怎么定义的呢?是指的绝对时间吗? ...
- iOS开发之动画编程的几种方法
iOS开发之动画编程的几种方法 IOS中的动画总结来说有五种:UIView<block>,CAAnimation<CABasicAnimation,CATransition,CAKe ...
- iOS 开发之动画篇 - 从 UIView 动画说起
毋庸置疑的:在iOS开发中,制作动画效果是最让开发者享受的环节之一.一个设计严谨.精细的动画效果能给用户耳目一新的效果,吸引他们的眼光 —— 这对于app而言是非常重要的. 本文作为动画文集的第一篇, ...
- iOS开发-动画总结
一.简介 IOS 动画主要是指Core Animation框架.官方使用文档地址为:Core Animation Guide.Core Animation是IOS和OS X平台上负责图形渲染与动画的基 ...
- ios开发核心动画七:核心动画与UIView动画的区别
/** UIView与核心动画区别?(掌握) 1.核心动画只作用在layer. 2.核心动画看到的都是假像,它并没有去修改UIView的真实位置. 什么时候使用核心动画? 1.当不需要与用户进行交互, ...
- iOS dateformatter设置GMT格式时间--iOS开发系列---项目中成长的知识四
今天在项目中开始接手客户端的签名这个模块,签名这个会在项目结束过后再单独写一下自己的心得! 今天讲讲在签名的过程中我们需要向服务器传送一个Date值,格式要求是格林威治时间,也就是GMT时间! 格式要 ...
- (转)iOS 开发,工程中混合使用 ARC 和非ARC
[前提知识] ARC:Automatic Reference Counting,自动引用计数 在开发 iOS 3 以及之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retain. ...
- iOS 开发,工程中混合使用 ARC 和非ARC(转)
[前提知识] ARC:Automatic Reference Counting,自动引用计数 在开发 iOS 3 以及之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retain. ...
- iOS开发CABasicAnimation动画理解
1.CALayer简介 CALayer是个与UIView很类似的概念,同样有backgroundColor.frame等相似的属性,我们可以将UIView看做一种特殊的CALayer.但实际上UIVi ...
随机推荐
- Python String模块详解
>>> import string >>> string.ascii_letters 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL ...
- VS2017与Qt5.7.0(静态库)环境基本配置
**************************************************************************************************** ...
- 手把手教你生成二维码-google.zxing
一.目标 输入网址,生成网址的二维码 二.概况 1.效果:UI丑,但功能实现了 2.项目目录 三.用到的第三方资源 1.google的扫码包zxing 2.JQuery 四.步骤(用myEclipse ...
- Windows下redis的安装与使用
Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...
- ECS 游戏架构 实现
转载自:http://blog.csdn.net/i_dovelemon/article/details/27230719 实现 组件-实体-系统 - 博客频道 这篇文章是在我前面文章,理解组件- ...
- 修改ubuntu密码
https://www.linuxidc.com/Linux/2016-05/131256.htm
- [SoapUI] 通过Groovy写文本文件
如果文件已经存在,先删除,然后向文件中追加失败信息 if(maxRecordFail>0){ def testResultFile = new File(projectDir+"\\T ...
- C# 基础连接已经关闭: 发送时发生错误
在程序中获取某个https网址的源码,GetRespose()时 出现了“基础连接已经关闭: 发送时发生错误.”的错误提示. 翻了论坛后,有个仁兄说: //.net 4 ...
- 两个线程并发执行以下代码,假设a是全局变量,那么以下输出______是不可能的?
3.两个线程并发执行以下代码,假设a是全局变量,那么以下输出______是不可能的? void foo(){ ++a; printf("%d ",a);}A.3 2 ...
- Windows下搭建JSP开发环境
1. 配置说明: => 编辑器: Eclipse (Java EE IDE) => 数据库: MySQL (MySQL Workbench 进行数据库管理, 用 MySQL Connect ...