本文转载至 http://www.cocoachina.com/ios/20151223/14739.html

感谢原创作者分享

前言
相信很多人对实现 iOS 中的动画效果都特别头疼,往往懒得动手,功能实现不就得了,何必要那么花哨、装13的东西。但是看到别人的炫酷动效,心中又瘙痒不已,便下定决心学习,于是开始翻看 Core Animation、UIView动画(其实是对Core Animation的一种封装)相关资料。不小心看到一群大神正在热烈讨论,钻一进去一看,原来是 POP(潜意识:Facebook出品必属精品),这还学什么Core Animation,果断pod一个来玩玩,于是你就左手CA,右手 POP 开森地把玩起来了。

此时,你可能已经学会了CA的基本使用方法,也对UIView动画的便捷感到惊喜,但是不满足的你,显然有更高的追求,POP 以其灵活的用法,丰富的动效,完整的API文档,深得很多程序员的喜爱。作为一个有逼格的程序员,这么流行的框架,必然是值得深入学习的,但是你是否考虑过这样的第三方动画框架是否存在什么不足。因此,作为一个有追求的程序员,有必要来稍微深入地探讨一下 Core Animation 和 POP 不同点。

Core Animation 工作机制

首先我们需要了解CA是如何工作的。每当我们创建并添加动画到 layer 时,QuartzCore 框架就会把动画的参数打包好,然后通过 IPC (处理器)发送给名为 backboardd 的后台处理程序。你的应用也会发送当前展示在屏幕上的每一个 layer 的信息。

backboardd 会处理 layer 的结构体系然后通过 OpenGL 绘制出来。它还会处理你已经添加过的动画(也可以是视图,因为视图本质是包裹着 layer的)。你一定要理解的是,backboardd 使得动画的每一帧都可以在你的应用中完全独立。这里唯一的回调是动画的开始和结束(详见CAAnimationDelegate 协议)。你的应用完全不会参与动画的绘制,这些绘制完全独立于你的应用进程(除非你明确地在你的应用中通过动画通用属性要求绘制动画帧)。这意味着你可以继续在主线程做其他事情,并且不会影响到 CAAnimation 的性能。如果你阻塞了你的主线程,或者你在调试器中暂停了你的程序,你的动画还是会继续执行。

但是你可能会有这样的疑问:每个 CALayer 不是还有一个 presentationLayer 属性吗?

presentationLayer的官方解释:

“While an animation is in progress, you can retrieve this object and use it to get the current values for those animations.”

当CAAnimation发生时,你在屏幕上看到的实际上是 presentation layer 的改变。如果你访问 presentation layer,QuartzCore 将会计算现有的帧状态,并且使用这个帧状态去构建 presentation layer 对象。因为动画状态在动画执行期间一直处于改变,因此你将会获得近似值。

POP 工作机制

现在有很多优秀的第三方动画库,POP 因为其使用灵活、功能强大、文档齐全,所以备受好评,先看一下官方介绍:

POP是一个在iOS与OS X上通用的极具扩展性的动画引擎 它在基本的静态动画的基础上增加的弹簧动画与衰减动画。

使之能创造出更真实更具物理性的交互动画 POP的API可以快速的与现有的ObjC代码集成并可以作用于任意对象的任意属性。

POP是个相当成熟且久经考验的框架 Facebook出品的令人惊叹的Paper应用中的所有动画和效果即出自POP。

更为详细的介绍和使用请查看官方文档以及里脊串的 POP介绍与使用实践(快速上手动画)

POP 本质上是基于定时器的动画库,使用每秒 60 频率的定时器,即时钟频率为 1/60 秒(为了匹配 iOS 显示屏帧率),使得动画刷新绘制频率与屏幕刷新频率一致。很多这类动画库都使用 CADisplayLink 做为一个回调源。

一旦定时器刷新,动画库计算动画的进程,这意味着动画库会计算那些活动的东西的状态(通常是layer 属性,如 bound,opactiy,transform 等)。然后动画库提供最新计算的值给有动画的 layer (或者其他对象)。最主要的区别是,layer 的状态将会在这种情况下改变。

由于 layer 的一些参数已经被改变,你的应用必须通过 IPC 通知 backboardd 处理这些变化。当 backboardd 接收到变化通知(同时接收到的还有应用中的 layer 树),它将在屏幕上重绘一切东西。这意味着,你应用中做的每一个动画帧都会传送数据到 backboardd (即通知 backboardd ),因为 backboardd 完全不知道 layer 发生了什么事情。综上,你的应用就是在这种情况下运行动画的。

Core Animation 和 POP 运行动画对比

由于 POP 是基于定时器定时刷新添加动画的原理,那么如果将动画库运行在主线程上,会由于线程阻塞的问题导致动画效果出现卡顿、不流畅的情况。更为关键的是,你不能将动画效果放在子线程,因为你不能将对 view 和 layer 的操作放到主线程之外。

为了验证上述的观点,我做了一个实验,首先用CA动画制作一个可以旋转的 view:

1
2
3
4
5
6
7
8
UIView *viewCA = [[UIView alloc]initWithFrame:CGRectMake(50,50, 100, 100)];
   viewCA.backgroundColor = [UIColor blueColor];
   [self.view addSubview:viewCA];
   CABasicAnimation *caAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
   caAnimation.toValue = @(M_PI);
   caAnimation.duration = 2.0;
   caAnimation.repeatCount = 500;
   [viewCA.layer addAnimation:caAnimation forKey:@"anim"];

再创建一个利用 POP 动画库制作的可旋转 view:

1
2
3
4
5
6
7
8
9
UIView *viewPOP = [[UIView alloc]initWithFrame:
CGRectMake(CGRectGetWidth(self.view.bounds) - 100 - 50, 50, 100, 100)];
   viewPOP.backgroundColor = [UIColor yellowColor];
   [self.view addSubview:viewPOP];
   POPBasicAnimation *popAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerRotation];
   popAnimation.toValue = @(M_PI);
   popAnimation.duration = 2.0;
   popAnimation.repeatCount = 500;
   [viewPOP.layer pop_addAnimation:popAnimation forKey:@"rotation"];

在没有线程阻塞的情况下,对比两个动画库的运行效果如下:

可以看出来虽然在没有线程阻塞,但是 POP 的动画在结束时有一个明显的停止动作,是因为 POP 的动画效果不好吗?

答案是 timingFunction

CoreAnimation 和 POPBasicAnimation提供同样的五种 timingFunction:

  • kCAMediaTimingFunctionLinear

  • kCAMediaTimingFunctionEaseIn

  • kCAMediaTimingFunctionEaseOut

  • kCAMediaTimingFunctionEaseInEaseOut

  • kCAMediaTimingFunctionDefault

重点说一下:kCAMediaTimingFunctionDefault(引自:iOS-Core-Animation-Advanced-Techniques(五)

它和kCAMediaTimingFunctionEaseInEaseOut很类似,但是加速和减速的过程都稍微有些慢。它和kCAMediaTimingFunctionEaseInEaseOut的区别很难察觉,可能是苹果觉得它对于隐式动画来说更适合(然后对UIKit就改变了想法,而是使用kCAMediaTimingFunctionEaseInEaseOut作为默认效果),虽然它的名字说是默认的,但还是要记住当创建显式的CAAnimation它并不是默认选项(换句话说,默认的图层行为动画用kCAMediaTimingFunctionDefault作为它们的计时方法)。

如果不设置 timingFunction 属性,那么在使用 CA 的情况下, timingFunction 是kCAMediaTimingFunctionLinear 的,而 POP 却是kCAMediaTimingFunctionEaseOut ,因此我们只要添加这么一行代码:

1
popAnimation.timingFunction?=?[CAMediaTimingFunction?functionWithName:kCAMediaTimingFunctionLinear];

现在再看效果:

可以看出来,在主线程没有阻塞的情况下,两种动画库的表现并无差异。

现在我们来制造一点难度,人工利用线程的 sleep 增加一个主线程阻塞:

1
2
3
4
5
6
- (void)repeatedlyBlockMainThread
{
    NSLog(@"blocking main thread!");
    [NSThread sleepForTimeInterval:0.25];
    [self performSelector:@selector(repeatedlyBlockMainThread) withObject:nil afterDelay:1];
}

然后再 viewDidLoad 里面调用 :

1
[self performSelector:@selector(repeatedlyBlockMainThread) withObject:nil afterDelay:1];

现在再来看一下两者的动画效果:

很明显,我们可以看出来,由于添加了主线程阻塞,利用 POP 制作的动画视图,在每隔 1s 都会卡顿一下,而 CA 的视图却完全不受主线程阻塞的影响。

总结

通过这次简单的对比,我们从工作机制上了解了 CA 和 POP 两个动画库的基本原理,并用简单的动画效果对比,重现了在主线程阻塞的情况下两者的差异,很显然, POP 受主线程阻塞的影响很大,在使用过程中,应避免在有可能发生主线程阻塞的情况下使用 POP ,避免制作卡顿的动画效果,产生不好的用户体验。文中提出了 POP 的这种缺点,但是 POP 毕竟是久经考验的动画技术,本人也正在学习中,有错误的地方吝请指正。

对比系列,是个人比较喜欢的一种学习方式,通过对比,找出不同技术的优缺点,可以更合理地使用这些武器,俗话说:好钢用在刀刃上,大抵如此。

iOS 动画效果:Core Animation & Facebook's pop的更多相关文章

  1. IOS动画(Core Animation)总结 (参考多方文章)

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

  2. iOS之核心动画(Core Animation)

      Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍.也就是说,使用少量的代码就可以实现非常强大的功能. Core ...

  3. IOS 核心动画(Core Animation)

    Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它 能做出非常炫丽的动画效果,而且往往是事半功倍.也就是说,使用少量的代码就 可以实现非常强大的功能. Core ...

  4. iOS Instruments之Core Animation动画性能调优(工具复选框选项介绍)

    Core Animation工具用来监测Core Animation性能.它给我们提供了周期性的FPS,并且考虑到了发生在程序之外的动画(见图12.4) Core Animation工具提供了一系列复 ...

  5. iOS动画效果和实现

    动画效果提供了状态或页面转换时流畅的用户体验,在iOS系统中,咱们不需要自己编写绘制动画的代码,Core Animation提供了丰富的api来实现你需要的动画效果. UIKit只用UIView来展示 ...

  6. iOS开发之Core Animation

    在IOS中如果使用普通的动画则可以使用UIKit提供的动画方式来实现,如果想实现更复杂的效果,则需要使用Core Animation了. 在Core Animation中我们经常使用的是 CABasi ...

  7. ios 动画效果CATransition笔记

    初学ios开发,很多概念还不清楚,所以只有边学边做例子.又怕学了后面忘了前面,因此用自己的博客来纪录自己的学习历程,也是对自己学习不要懈怠做个监督. 刚学ios做动画效果.因为ios封装得很好,实现i ...

  8. AndroidUI 视图动画-自定义动画效果 (Animation)

    如果Android提供的四种动画 效果 和混合动画效果 不能够 满足需求的话,可以使用自定义动画效果 : 新建一个类CustomAnimation 使其继承自 android.view.animati ...

  9. CSS动画效果之animation

    Y(^o^)Y css动画大乱弹之animation. 概述 什么是animation呢?在回答这个问题之前,先要说明什么叫做@keyframe(关键帧).@keyframe算是一个动画模板.在其中, ...

随机推荐

  1. ABAP--如何创建自定义打印条码

    ABAP--如何创建自定义打印条码 BARCODE in Smartforms: How to create customize BARCODE for Smartforms. 1 Introduct ...

  2. (原创)Python文件与文件系统系列(3)——os.path模块

    os.path 模块实现了一些操作路径名字符串的函数,可以通过 import os.path 使用该模块,不过即使仅仅 import os 也可以使用该模块的方法. 1. abspath(path) ...

  3. HttpClient后台post 请求webapi

    1.请求方法 /// <summary> /// httpClient 请求接口 /// </summary> /// <param name="url&quo ...

  4. Couchbase 集群小实践

    局域网 两台机  192.168.1.2  我们称为A机器   192.168.1.3   我们称为B机器   配置集群的时候,从A或者是B的web后台都可以添加, 在这里 我们以 A机器为主   目 ...

  5. mybatis 参数为String,用_parameter 取值

    mybatis 参数为String,if test读取该参数代码: <select id="getMaxDepartId" parameterType="java. ...

  6. 设置更改root密码 连接mysql mysql常用命令

  7. 单用户模式&救援模式&克隆虚拟机&Linux机器相互登录

    1.13 单用户模式 1.14 救援模式 1.15 克隆虚拟机 1.16 Linux机器相互登录 1.单用户模式 关机:init 0 .poweroff 重启:init 6 .reboot 关机:in ...

  8. MD5 哈希等各种加密方式 都是对这个对象进行各种运算, 然后得出1个字符串

    你列出的4个  都是对对象的 加密算法

  9. storm学习之七-storm UI页面参数详解

    http://lbxc.iteye.com/blog/1522318 --参考文章 http://blog.csdn.net/rong_89/article/details/39473917 --参考 ...

  10. 自动换行后缩进怎么做(CSS)?(可用于 Li y 元素的排版)

    <style type="text/css">li{ width:100px; border:1px solid #ccc; padding-left:25px; te ...