本文转载至 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. 通过C#脚本实现旋转的立方体

    一.介绍 目的:通过一个简单的例子(鼠标点击,使立方体旋转和变色)熟悉Unity中C#脚本的编写. 软件环境:Unity 2017.3.0f3 . VS2013. 二.C#脚本实现 1,启动Unity ...

  2. win32 数据类型 vs c#

    在C#中做很多应用需要使用win32 API,但发现原型函数的一些数据类型看起来非常费劲,甚至在C#中“没有”这种数据类型,查阅了一下资料,数据类型对应关系整理如下,希望对大家有用: BOOL=Sys ...

  3. perl学习-运算符添加引号

    这个比较有意思,在其它语言中好像没有特别提到 Perl 引号运算符如下表所示. 运算符描述实例 q{ }为字符串添加单引号q{abcd} 结果为 'abcd' qq{ }为字符串添加双引号qq{abc ...

  4. 在Ubuntu14.04上编译Android4.0.1出现的几个问题

    一. 工具 sudo apt-get install git-core gnupg flex bison gperf build-essential \       zip curl libc6-de ...

  5. IE10弹窗showModalDialog关闭之后提示SCRIPT5011:不能执行已释放的Script代码

    在Web开发中,经常使用showModalDialog弹窗 今天遇到一个小问题,IE10中弹窗关闭之后提示SCRIPT5011:不能执行已释放的Script代码 网上搜罗了一些资料,发现大多都提到对象 ...

  6. 使用DUPLICATE 方式创建ORACLE 11G DG备库环境

    我的最佳实践 ① 手动创建好初始化参数文件: *.audit_file_dest='E:\APP\XJXU\ADMIN\ORASTAND\ADUMP'*.control_files='E:\APP\X ...

  7. SQL2000系统表、存储过程、函数的功能介绍及应用

    转自:http://blog.csdn.net/zlp321002/article/details/480925 ----系统表------------------------------------ ...

  8. Gridview中的选择、删除、编辑、更新、取消留着备用。

    后台程序: public partial class tw2 : System.Web.UI.Page{    protected void Page_Load(object sender, Even ...

  9. kafka_2.10-0.8.1.1.tgz的1或3节点集群的下载、安装和配置(图文详细教程)绝对干货

    运行kafka ,需要依赖 zookeeper,你可以使用已有的 zookeeper 集群或者利用 kafka自带的zookeeper. 单机模式,用的是kafka自带的zookeeper, 分布式模 ...

  10. 不确定行数的多行文本垂直水平居中的css

    ul li { position:relative; display: table; width:3rem; height:3rem; background:url('image/defaultBg. ...