一、引言

在iOS开发中使用动画时,可以通过设置动画的durationspeedbegintimeoffset属性,来设置动画的时长、速度、起始时间及起始偏移。
用一个简单的例子来说明各个参数的的作用。动画很简单,一个红色的方块从左移到右边。动画的持续时间是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];

做修改以后,效果如下:

与上面相比,三处不同

  1. 动画的速度是原来的两倍。
  2. 点击开始动画的按钮,到开始动画,有一个延迟。
  3. 动画起始时,滑块的位置为中央,而不是在左边。

我们已经看到了这些属性的效果。翻阅文档,发现begintimespeed等属性是CAMediaTiming这协议的属性,并且CALayerCAAnimation都遵守了CAMediaTiming协议。
那么CAMediaTiming协议是什么呢?有什么作用呢?

二、层级时间结构

根据文档,CMediaTiming协议构建了一个层级的时间系统,并用这个层级的时间系统来协调各个layer、animation的时间。
这个协议被CAAnimationCALayer遵守,每一个遵守协议的的object对应一个time space。根据object之间的关系,不同的time space有层级关系。比如Layer A有一个subLayer B,那么Layer A对应的time space就是layer B对应的time spaceparent time space。每一个time space中时间的数值都是根据parent time space的数值,以及begintimespeed等属性,根据一定的规则来计算的。

为了便于理解层级时间系统,先看下layer在屏幕上的显示位置是如何确定的,然后做一个类比。

layer层级如上。要确定sublayer1在屏幕上的显示位置,一共分三步。

  1. 确定window layer在屏幕位置position1
  2. 根据position1及view layer的position属性,确定view layer在屏幕中的位置position2
  3. 根据position2及sublayer1的position属性,确定sublayer1在屏幕中的位置position3

与此类似,要确定sub1ayer1中的time,也要分三步。

  1. 确定window layer中的time1
  2. 根据time1及view layer的begintimeoffset等属性计算出view layer中的time2
  3. 根据time2及sublayer1的begintimeoffset等属性计算出sublayer中的time3

和确定layer的位置相比,确定时间有一些复杂,主要提现在下面两点

  1. 层级时间系统的构成复杂。
    layer tree的每一级都是CALayer,而只要遵守CAMediaTiming协议,就可以作为层级时间系统的一部分。比如CALayerCAAnimation(及其子类CAAnimationGroup)都可以作为层级时间系统的一部分。
  2. 不同层级之间时间转换规则复杂
    计算当前layer的位置时,只需要知道父layer的位置,以及当前layer的position属性。计算当前层级时间时,不仅需要知道上一个层级的时间,还需要知道当前层级的begintimeoffsetspeed等属性。转换的规则也比较复杂,要经历两次转换。从parent timeactive local time,再到basic local time

三、active local time

这次转换是为了处理当前层级的object在父层级的的时间线上的位置,以及当前层级和父层级之间时间流逝速度的关系。
和这次转换相关的属性有beginTimespeed以及timeOffset

  1. begin time
    子层级相对于父层级的起始时间。也就是父层级的时间经过多久,子层级才开始计算时间。
    比如子层级A被加入层级时间系统时,它父层级B的时间是5s,子层级A的begintime是6s,那么当它父层级的时间变为6s时,子层级才开始计算时间。
  2. speed
    子层级相对于父层级的时间流逝速度。如果speed是2,那么当父层级的时间增加了10s时,子层级的时间增加了20s(10s的2倍)。
  3. timeOffset
    为本地时间增加一个偏移。 如果timeOffset是5s,那么本地时间的起始就是5s。

parent timeactive 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,因此当前是动画展示一半的状态。

  1. repeatCountrepeatDuration
    当前的层级要重复的次数或重复的时间,两者不可同时指定。
    以动画为例,如果指定repeatCount,那么指定了动画要重复几次。如果指定了repeatDuration,那么指定了动画重复的时间。
  2. autoreverses
    在重复之前是否要倒放。

五、文首的例子

根据这些知识,可以解释文章开始时设置参数的效果。
当动画被加到layer上时,动画对应的time space被加到层级时间系统中,是layer对应的time space的子层级。

  1. 动画的速度是原来的两倍
    设置动画的speed是2,这样子动画中的时间流逝速度时layer中时间流逝速度的2倍。当layer中时间经过0.5s时,动画中时间已经流逝了1s,动画已经完成了。(动画的duration是1s)
  2. 点击开始动画的按钮,到开始动画,有一个延迟
    我们首先得到了当前layer的时间addtime,然后把动画的begintime设置为addtime+0.3。这样子当动画被加到layer之后0.3s,layer中的时间是addtime+0.3,此时动画中的时间才开始计算,之前动画没有开始。
  3. 动画起始时,滑块的位置为中央,而不是在左边
    我们设置了动画的offset为0.5s。当动画开始时,动画对应的time space的时间是0.5s,对应动画duration的一半,即滑块位置在屏幕中央。

六、更多应用

了解了CAMediaTiming协议后,可以实现很多动画的效果。

  1. 让某一个layer上的动画停止
    设置layer的speed为0即可。
  2. 实现门打开然后关闭的效果
    实现一个门打开的动画,然后把动画的autoreverses属性设置为YES即可。
  3. layer上的若干动画依次延迟启动
    分别设置这些动画的beginTime为不同的值即可
  4. 手动控制动画的进度
    设置动画的speed为0,然后改变动画的offset即可。

苹果已经把工具给我们了,可以做出什么样的产品就看大家的想象力了。

参考

控制动画时间
控制动画时间(上文的中文版)
Time Warp in Animation

iOS开发之动画中的时间(概况)的更多相关文章

  1. iOS开发之动画中的时间

    概述 在动画中,我们会指定动画的持续时间.例如 scaleAnimation.duration = self.config.appearDuration 那么这个时间是怎么定义的呢?是指的绝对时间吗? ...

  2. iOS开发之动画编程的几种方法

    iOS开发之动画编程的几种方法 IOS中的动画总结来说有五种:UIView<block>,CAAnimation<CABasicAnimation,CATransition,CAKe ...

  3. iOS 开发之动画篇 - 从 UIView 动画说起

    毋庸置疑的:在iOS开发中,制作动画效果是最让开发者享受的环节之一.一个设计严谨.精细的动画效果能给用户耳目一新的效果,吸引他们的眼光 —— 这对于app而言是非常重要的. 本文作为动画文集的第一篇, ...

  4. iOS开发-动画总结

    一.简介 IOS 动画主要是指Core Animation框架.官方使用文档地址为:Core Animation Guide.Core Animation是IOS和OS X平台上负责图形渲染与动画的基 ...

  5. ios开发核心动画七:核心动画与UIView动画的区别

    /** UIView与核心动画区别?(掌握) 1.核心动画只作用在layer. 2.核心动画看到的都是假像,它并没有去修改UIView的真实位置. 什么时候使用核心动画? 1.当不需要与用户进行交互, ...

  6. iOS dateformatter设置GMT格式时间--iOS开发系列---项目中成长的知识四

    今天在项目中开始接手客户端的签名这个模块,签名这个会在项目结束过后再单独写一下自己的心得! 今天讲讲在签名的过程中我们需要向服务器传送一个Date值,格式要求是格林威治时间,也就是GMT时间! 格式要 ...

  7. (转)iOS 开发,工程中混合使用 ARC 和非ARC

    [前提知识] ARC:Automatic Reference Counting,自动引用计数 在开发 iOS 3 以及之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retain. ...

  8. iOS 开发,工程中混合使用 ARC 和非ARC(转)

    [前提知识] ARC:Automatic Reference Counting,自动引用计数 在开发 iOS 3 以及之前的版本的项目时我们要自己负责使用引用计数来管理内存,比如要手动 retain. ...

  9. iOS开发CABasicAnimation动画理解

    1.CALayer简介 CALayer是个与UIView很类似的概念,同样有backgroundColor.frame等相似的属性,我们可以将UIView看做一种特殊的CALayer.但实际上UIVi ...

随机推荐

  1. Ros学习——Cmakelists.txt文件解读

    1.过程 .Required CMake Version (cmake_minimum_required) //CMake 需要的版本 .Package Name (project()) //#定义工 ...

  2. 混合开发之DSBridge(同时支持Android和iOS)

    什么是 Javascript bridge 随着h5的不断普及及优化,以及移动端对动态化的需求越来越大,开发者经常需要在app中嵌入一些网页,然后会在web和native之间进行交互,如传递数据,调用 ...

  3. 13-Oulipo(kmp裸题)

    http://acm.hdu.edu.cn/showproblem.php?pid=1686 Oulipo Time Limit: 3000/1000 MS (Java/Others)    Memo ...

  4. JMS学习之理论基础

    本文代码使用ActiveMq5.6 一.什么是JMS JMS(Java Message Service,Java消息服务)是一组Java应用程序接口(Java API),它提供创建.发送.接收.读取消 ...

  5. 没有Reduce的MapReduce(一)

    尝试了一个没有Reduce的MapReduce. [应用场景]: 从Hbase的A表中进行数据抽样,直接输出到B表中. 这种场景下,相当于只进行了一个数据检索,本来是用Hive就可以实现,但是考虑到业 ...

  6. Smarty模板的引用

    (1)include用法和php里的include差不多(2)smarty的include还具备自定义属性的功能例如 {include file="header.tpl" titl ...

  7. MSSQLServer 存储过程

    一直对存储过程懵懵懂懂,翻了资料,觉得存储过程大有用处. 1.改善性能 SQL语句的执行需要先编译在执行,存储过程就是一组为了完成特定功能的SQL语句集,他可以一次编译,下次执行不再编译,提高运行效率 ...

  8. 第02章 查询DSL进阶

    本章内容 Lucene默认评分公式是如何工作的. 什么是查询重写. 查询二次评分是如何工作的. 如何在单次请求中实现批量准实时读取操作. 如何在单次请求中发送多个查询. 如何对包括嵌套文档和多值字段的 ...

  9. Leaflet入门:添加点线面并导入GeoJSON数据|Tutorial of Leaflet: Adding Points, Lines, Polygons and Import GeoJSON File

    Web GIS系列: 1.搭建简易Web GIS网站:使用GeoServer+PostgreSQL+PostGIS+OpenLayers3 2.使用GeoServer+QGIS发布WMTS服务 3.使 ...

  10. Appium常用API(一)

    Appium作为当下一款移动应用的自动化测试工具,对于测试来说重要性不言可寓,废话不多说,下面总结下它常用的API: 1.contextscontexts(self): Returns the con ...