Core Animation基本概念和Additive Animation

[http://www.cocoachina.com/applenews/devnews/2014/0701/8995.html]

到Core Animation不能不说Layer,一个个Layer通过tree的结构组织起来,在Display的过程中实际上有3种Layer tree。1、model layer tree;2、presentation tree;3、render tree

转自不会开机的男孩的博客

 

Core Animation

说到Core Animation不能不说Layer,一个个Layer通过tree的结构组织起来,在Display的过程中实际上有3种Layer tree。
 
1、model layer tree
2、presentation tree
3、render tree
 
model Layer tree中的Layer是我们通常意义说的Layer。当我们修改layer中的属性时,就会立刻修改model layer tree。
     
     
  1. layer.position = CGPointMake(0,0); //这里的修改会直接影响model layer tree 
presentation tree是Layer在屏幕中的真实位置。比如我们创建一个动画
     
     
  1. [UIView animateWithDuration:5.0f 
  2.                   animations:^{ 
  3.                     self.animationLabel.center = CGPointMake(200, 400); 
  4.                   }]; 
  5.  
  6.  //这里用一个Timer print presentLayer的位置。 
  7.  CALayer *layer = self.animationLabel.layer.presentationLayer; 
  8.  
  9.  NSLog(@"model:%@, presentLayer%@", NSStringFromCGPoint(self.animationLabel.layer.position), NSStringFromCGPoint(layer.position)); 
下面是屏幕输出结果
     
     
  1. model:{73.5, 155.5}, presentLayer{73.5, 155.5} 
  2. model:{200, 400}, presentLayer{73.559769, 155.61552}//开始动画 
  3. model:{200, 400}, presentLayer{73.814095, 156.10709} 
  4. model:{200, 400}, presentLayer{74.267357, 156.98315} 
  5. ... 
  6. ... 
  7. ... 
  8. model:{200, 400}, presentLayer{199.99576, 399.99182} 
  9. model:{200, 400}, presentLayer{200, 400} 
Note: render tree 在apple的render server进程中,是真正处理动画的地方。而且线程的优先级也比我们主线程优先级高。所以有时候即使我们的App主线程busy,依然不会影响到手机屏幕的绘制工作。
 
CADisplayLink
了解 cocos2dx对CADisplayLink一点也不陌生,对APP开发者可能就有一点远,但是facebook的Pop一下子拉近了我们和CADisplayLink的距离。通过设置callback函数,当屏幕刷新的时候,就可以执行我们的代码。当然,我们也可以利用NSTimer 或是GCD来实现类似的功能。但是CADisplayLink是最优的,因为不管是哪种类型的Timer,即使我们的刷新间隔和屏幕刷新保持一致。我们都无法知道系统什么时候刷新屏幕。
 
1-1 NSTimer中每一帧其实只有8ms的时间,如果大于8ms,那么就会丢帧
 
facebook的 Pop非常类似UIDynamic,但是我们需要注意一点,相对于传统的model动画来说,CADisplayLink导致部分绘制工作放在了我们APP的地址空间中,也就是说,增大了APP内存,CPU的开销。也更容易遇到性能瓶颈。
 
Note: model layer的这部分绘制是完全在render server,而render server运行在比APP更高优先级的进程中,而这个也意味着会有进程间通讯的开销。传递的数据包括整个render tree还有动画,所以,Apple 并不推荐我们手动commit transaction, Core Animation 默认会在run loop 中提交transaction。
 
UIView animation
Apple 最近在推荐一些Modern APP的设计,其中有一条是希望responsive。比如下面的场景,启动一个动画之后,在动画还没有完成之前取消这个动画。
 
 
这里我们看到了3种情况。
 
红色的2个动画之间有一个很大的跳动。
绿色的比红色的好一点,没有跳动,但是就像撞到了墙一样,完全丧失了一开始动画的速度。
蓝色的的运动更加平滑,有更真实的物理效果。
 
UIKit创建的动画,系统是如何理解的
UIKit的动画最后都会通过Core Animation 来实现, 那么当我们修改layer(model layer)的数值时,系统是如何理解并创建动画呢? 比如这里有一个线性的动画,将animationView的坐标从(0,0)移动到(0,500)
     
     
  1. animationView.center = CGPointMake(0, 0); 
  2.  [UIView animateWithDuration:1.0f 
  3.                      delay:0 
  4.                    options:UIViewAnimationOptionCurveLinear 
  5.                 animations:^{ 
  6.                   animationView.center = CGPointMake(0, 500); 
  7.                 } completion:^(BOOL finished) { 
  8.  
  9.                 }]; 
 
下面是当我们创建一个UIKit的动画时发生的事情
 
 
Model:在animationView.center = CGPointMake(0, 500);之后会立刻修改animationView的model Layer中的position的值为(0, 500)。
Animation:系统的理解就是从原来的model layer的值(0,0)到新的model layer的值(0, 500)创建一个动画。
Presentation: Presentation就像上面提到的,是表示animationView当前在屏幕的真实位置(渲染位置),因为还没有”动”起来,所以还是(0,0)
 
Note: Animation的部分如果没有明白,可以结合后面的回头再看
 
当我们看到屏幕上面的View移动的时候,发生了下面的事情
这是在0.4s时刻之前的状态。Model Layer的数值没有变化,而Presentation则在变化,和真正的屏幕动画保持一致。
在一个animation并没有完成的情况下,再创建一个动画系统是如何理解的呢?
如果我们在0.5时刻创建一个reverse动画,animationView.center = CGPointMake(0, 0);
     
     
  1. [UIView animateWithDuration:1.0f 
  2.                       delay:0 
  3.                     options:UIViewAnimationOptionCurveLinear 
  4.                  animations:^{ 
  5.                    animationView.center = CGPointMake(0, 0); 
  6.                  } completion:^(BOOL finished) { 
  7.  
  8.                  }]; 
Model:的数值会被立刻修改成目标数值(0, 0)
Animation: 系统的理解是从原来的(0, 500),创建一个去(0,0)的动画
Presentation: 基于系统的理解,Presentation layer的数值变成了(0, 500)。1秒中的时间内递减到(0, 0)
 
到目前为止,我们可以清楚的理解为什么红色的view会有一个大的跳跃,在我们这里的理解就是presentation layer的一个不连续的修改。
 
绿色的动画效果原因
在上面的基础之前,绿色的就可以简单说一些
 
 
Model 这里还是和之前一样,表示目标值
Animation:系统的理解是从当前的动画位置开始,也就是 (0, 150)开始创建一个1秒的动画到(0,0)
Presentation 和我们的预期一样。
 
linear animation 图中的颜色和本文的颜色无关,只是表示2个动画的stage 
EseInOut animation 图中的颜色和本文的颜色无关,只是表示2个动画的stage
 
可以看出来2个动画相接的曲线不平滑,而造成这个不平滑的原因在于把之前的动画覆盖了, 丢掉了之前动画的速度,如果要实现一个更一般化的解决方案,我们很自然的想到了动画合成。
 
蓝色的动画原因
蓝色的动画比较复杂,使用了Core Animation中的additive属性,动画被设置成相对的,那么就和动画具体的位置无关。最后还合成了2个动画。
 
首先,解释一下什么是相对的动画。
这里很容易看到,view的真实位置是Animation 的值 + Model的值。系统的理解就是相对目标值(0, 500)来说,创建一个从-500 到 0 的动画。
 
其次,相比之前的动画,在0.6时刻(为了方便计算,把之前的0.5时刻移动到了0.6时刻)并没有删除掉之前的动画,而是添加了一个新的动画Animation2。也就是一个相对目标值(0,0)来说,创建一个从500到0的动画。整个运动变成了2个动画的合成。
Note: Animation2的duration修改了,在demo code里面并没有修改 :)
 
这里,我们就得到了一个一般化的解决方案。
图中的颜色和本文的颜色无关,只是表示2个动画的stage
 
iOS 8的改动
Core Animation 有一个additive的属性实际上已经存在很久了,但是却很少被大家知道(我自己也是)。在iOS8 之前,UIKit创建的动画默认是不使用additive的,而在iOS8之后,默认是Additive的。有兴趣的同学可以试一试download demo code用Xcode6(这会还是beta)并打开macro#define USING_UIKIT 1看一下新的UIKit animation效果。
 
在了解背后的机制之后,其中的变化也很容易理解。
 
1、completion block 的调用变了。之前在创建一个UIKit的动画时候,会覆盖掉上一个动画,也就是删除再添加一个新动画,而现在前一个动画会在真正执行完毕才会执行completion block。
 
2、不是所有的动画都支持additive
 

 参考

 

《WWDC2014 236_building_interruptible_and_responsive_interactions》

 

《Core Animation Programming Guide:Core Animation Basics》

 

《additive-core-animation》


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值