Core Animation

这篇我们来讨论下Core Animation的原理和在iOS开发中的应用.

Core Animation原理

Core Animation是用来展示view或者其他可见元素动画的机制。有了Core Animation(以下简称CA), 开发人员只需要配置一些简单的动画参数就能够创建出流畅的原生动画,例如开始位置,结束位置(basic core animation类)等等. 在Apple的框架中,Core Animation所处位置如下图所示:

CA结构

可以看到,CA位于UIKit和AppKit下方,算是一个较为底层的框架。CA存在于QuartzCore framework,这里面也包含一些OpenGL和Graphics的子框架。这些框架会将生成的动画、图片等图像信息传给底层的绘图硬件(caching成bitmap),产生最终用户看到的界面。

CA涉及两个部分,一是CALayer, 另一个是Animation. 我们先来讲CALayer。

CALayer

在iOS中,UIView是我们我们最常用的一个类,整个的UIView是建立在CA层上的,每个UIView及其子类都存在一个layer层(root layer)。这个层是干什么的呢?
相信你们或多或少都写过这样的代码吧:

 demoLabel.layer.cornerRadius = 5.f;
 demoLabel.layer.borderColor = []UIColor grayColor];
 demoLabel.layer.borderWidth = 1.f;

代码中的layer就是CALayer。 CALayer是用来管理布局属性的,即用户可见部分,也就是说,我们看到的一个个label, textView,button都是CALayer帮助我们画出的,而UIView,UITextView以及UIButton都是CALayer的一个封装,为其提供了事件响应能力。当然,平常我们写代码时,一些简单的可见属性例如background color是可以用UIView本身来设置的,但是一旦涉及到复杂精细的界面效果, 则非CALayer莫属。

在本篇中,我们不讲述CALayer是如何在iOS和OSX中的布局方式和不同的坐标系统,若您想了解的话,可点击以下两个链接: 有<a href="http://www.jianshu.com/p/c6714dda9a9c">中文版</a>和<a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/CoreAnimationBasics/CoreAnimationBasics.html#//apple_ref/doc/uid/TP40004514-CH2-SW3">英文版</a>可供选择,英文是Apple Doc里的,官方内容; 中文版来自简书。在本篇中,我们偏向更理论的部分。

和UIView一样,layer也有树形结构,也有sublayer, superlayer之分。我们可以参考下图:

Layer层级

如图所示,我们可以像添加subview一样添加sublayer,最终产生的效果是一样的。 而且右侧的layer树也和UIView的层级树一样自顶向下。本质上说,UIView的层级树都会转换成layer的树形结构, 交给底层的绘图硬件去处理,性能也因此得到了极大的提升。

CALayer,或者说我们经常说的layer,本质上是一个model tree,它是系统用来存储当前属性的object,例如一些动画的target value, 起始值,结束值等等。但是,在CA中的CALayer可不止一个model tree,还有2个,分别是presentation tree和render tree。它们3个分别反映了动画状态的不同方面。我们之前已经说过model tree用来存储一些静态属性,平常我们的赋值操作就是直接和model tree进行交互。与此同时,presentation和render tree中也生成了和model tree相同的对应树形结构,为将来动画展示做准备。不同的是,render tree是私有的object, 对我们不可见,被用来渲染动画(数据), 其运行的线程在比当前app主线程优先级还高,是在Apple的render server进程中进行的渲染,不会造成主线程堵塞。细心地你当然也会发现这样会增加进程间通讯的开销,所以Apple不建议开发者手动commit transaction而是默认在run loop中提交事务(进程间传递的数据主要有整个render tree和对应的动画)。 三种tree关系如下图所示:

3中layer对比

CALayer中还有个比较重要的概念就是它具有层级关系的时间系统, CALayer实现了CAMediaTiming协议,用来控制动画的展示等,例如暂停和恢复。这部分内容我们另起一篇讲.

Animation

众所周知,Apple的对动画的处理真是流畅之极,细腻的也恰到好处。比方说,对于root layer来说,添加动画一般会调用UIViewAnimationWithBlocks这个category中的animateWithDuration系列方法, 使用者只需要在callback中写入想执行动画的代码即可.类似spring这样的具有damping效果的动画也可以这样添加。

但是,这些都是较为简单的动画,而且针对的是root layer。那如果我们的layer是我们自己添加的sublayer该怎么办呢?答案也很简单,添加显式动画。之前提供的那个<a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/CoreAnimationBasics/CoreAnimationBasics.html#//apple_ref/doc/uid/TP40004514-CH2-SW3">中文版</a>链接中有不同layer添加动画的demo code, 包括设置各种不同属性等等,大家可以参考。我在这里更多的是探讨下Animation的结构.

Animation结构

显式动画的基类为CAAnimation,常用的是CABasicAnimation, CAKeyframeAnimation有时候还会使用到CAAnimationGroup来做组合动画. 不过我们这次只讲比较重要的CABasicAnimation和CAKeyframeAnimation,其他的有机会再讲。

不管是CABasicAnimation还是CAKeyframeAnimation都是继承于CAPropertyAnimation.


Basic Animation

图中有3个属性, fromValue, toValue和interpolated point.这三个都是可选的, 但是不得同时多于2个为非空,一般来说,我们仅指定起始点和终点即可,中间的值由timing function插值计算出来, 默认是线性变换. Timing function是控制插值计算的,形象点说是Timing Function决定了动画运行的节奏(Pacing), 比如是均匀变化(相同时间变化量相同),先快后慢,先慢后快还是先慢再快再慢. 例如我们在给view添加动画时,会指定一些option例如 curveIn, curverOut, flip等等,这些其实实现时都是依靠时间函数来实现。时间函数本质是映射,决定了时间和对应的变化量,例如一秒内透明度的变化. 当使用basicAnimation时, 自定义的timing function可以是一条光滑的贝塞尔曲线, 由起点,终点和2个关键点控制: 如下图:

贝塞尔曲线

但是如果动画比较复杂, 既不是直线,也不是贝塞尔曲线, 那么就需要通过CAKeyframeAnimation来实现. 关键帧动画很强大,可以让我们充分的实现我们自定义的动画效果,例如落叶的飘落,纵向翻转(转场动画)等等。当然你可以用嵌套basicAnimation的方式实现(平移+旋转),但是那样既复杂,代码不简洁,而且动画很生硬。但Apple给了我们解决方案---keyFrame Animation!

 + (void)animateKeyframesWithDuration:(NSTimeInterval)duration 
                                delay:(NSTimeInterval)delay 
                              options:(UIViewKeyframeAnimationOptions)options 
                           animations:(void (^)(void))animations 
                           completion:(void (^__nullable)(BOOL finished))completion

+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime 
                        relativeDuration:(double)frameDuration 
                              animations:(void (^)(void))animations
  1. frameStartTime 表示关键帧动画开始的时刻在整个动画中的百分比
  2. frameDuration 表示这个关键帧动画占用整个动画时长的百分比

我们需要做的就是在第一个方法中添加关键帧, 设定开始时间和持续时间, 并在animation callback中设置某个keyFrame结束时的view位置,透明度等等, 之后,系统会为我们插入中间帧, 确保动画的平滑。在关键帧动画中还有一个非常重要的参数,那便是calculationMode,计算模式. 他决定插值的方式: 即当在平面座标系中有多个离散的点的时候,可以是离散的,也可以直线相连后进行插值计算,也可以使用圆滑的曲线将他们相连后进行插值计算:

  1. UIViewKeyframeAnimationOptionCalculationModeLinear // 连续运算模式,线性
  2. UIViewKeyframeAnimationOptionCalculationModeDiscrete // 离散运算模式,只显示关键帧
  3. UIViewKeyframeAnimationOptionCalculationModePaced // 均匀执行运算模式,线性
  4. UIViewKeyframeAnimationOptionCalculationModeCubic // 平滑运算模式
  5. UIViewKeyframeAnimationOptionCalculationModeCubicPaced // 平滑均匀运算模式

总结

Apple的CoreAnimation由两部分组成: CALayer和Animation. 它们两个分别确保了view的显示和动画的平滑。深刻理解core animation的原理不仅有助于我们调试代码, 理解他们之间的关系,更可以帮助我们创造出优美且性能优越的动画, 提升用户体验.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 书写的很好,翻译的也棒!感谢译者,感谢感谢! iOS-Core-Animation-Advanced-Techni...
    钱嘘嘘阅读 2,293评论 0 6
  • 个人博客地址:Lixuzong's Blog 我们所在屏幕上看到的都是Core Animation框架提供的,所以...
    猿鹿说阅读 450评论 0 1
  • 核心动画(Core Animation)一、Core animation简单介绍 1.Core Animatio...
    北辰青阅读 1,010评论 0 1
  • 我们写的应用程序往往都不是静态的,因为它们需要适应用户的需求以及为执行各种任务而改变状态。 在这些状态之间转换时,...
    sunmumu1222阅读 696评论 0 2
  • 2014年,我去了敦煌,一个人去的,没有和林欢,那个时候我们已经分手三年了。 其实我没有资格说分手这两个字,我从来...
    熊猫微刊阅读 212评论 0 5