Core Animation 的隐式动画

来源:互联网 发布:ubuntu搭建openstack 编辑:程序博客网 时间:2024/05/17 12:21

场景重现:为什么UIView或者CALayer改变他们相关属性,他们就会平缓的做些动画,这时你并没有调用相关动画代码,想过这个问题没?

那我们来看看系统究竟帮我们做了哪些东西。

如果你自己设置了动画类型和动画时间,表现出来就是你指定的动画,如果没有,那么系统会自动帮我们做了动画类型和动画时间(这就是隐式动画)。

问题有来了,什么决定了动画时间和动画类型。
1、动画时间: 当前”事务” 决定的 ==>“事务“是通过CATransaction类来做管理。
2、动画类型:由图层的行为决定的。

note:CATransaction概念
CATransaction没有属性或者实例方法,并且也不能用+alloc和-init方法创建它。但是可以用+begin和+commit分别来入栈或者出栈

隐式动画真正背后执行的原因:

Core Animation在每个run loop周期中自动开始一次新的事务(run loop是iOS负责收集用户输入,处理定时器或者网络事件并且重新绘制屏幕的东西),即使你不显式的用[CATransaction begin]开始一次事务,任何在一次run loop循环中属性的改变都会被集中起来,然后做一次0.25秒的动画。

如果你不用系统的动画模式,要自定义,最原始的样子就是下面

- (IBAction)changeColor{    //begin a new transaction    [CATransaction begin];    //set the animation duration to 1 second    [CATransaction setAnimationDuration:1.0];    //randomize the layer background color    CGFloat red = arc4random() / (CGFloat)INT_MAX;    CGFloat green = arc4random() / (CGFloat)INT_MAX;    CGFloat blue = arc4random() / (CGFloat)INT_MAX;    self.colorLayer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;    //commit the transaction    [CATransaction commit];}

上面讨论所有的问题,都是动画时间相关的,还有个影响动画的因素,刚才的第二点:动画类型(由图层决定了)

动画类型(由图层决定)

先上代码,让大家看看问题。

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    self.layerView.layer.backgroundColor = [UIColor blueColor].CGColor;//这里直接给view的layer层设置了颜色}- (IBAction)changeColor{    //begin a new transaction    [CATransaction begin];    //set the animation duration to 1 second    [CATransaction setAnimationDuration:1.0];    //randomize the layer background color    CGFloat red = arc4random() / (CGFloat)INT_MAX;    CGFloat green = arc4random() / (CGFloat)INT_MAX;    CGFloat blue = arc4random() / (CGFloat)INT_MAX;    self.layerView.layer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;    //commit the transaction    [CATransaction commit];}

运行程序,你会发现当按下按钮,图层颜色瞬间切换到新的值,而不是之前平滑过渡的动画。发生了什么呢?

先给结论:
1、是给UIView做的动画,那么一定要用UIView层的动画模式(UIView有两个方法,+beginAnimations:context:和+commitAnimations)。
2、是给CALayer做动画,那么一定用CATransaction begin相关的方法。

原因就是上面程序出现的问题:UIView关联的图层禁用了隐式动画,造成了动画没有。

再深入一点,隐式动画是如何被UIKit禁用掉呢?
解决这个问题,先看看这个系统大概是如何实现隐式动画?

CALayer的属性被修改时候,layer首先检测它是否有委托,
1、有代理对象,它会调用-actionForKey:方法,
2、没有代理对象,去找图层动画的action(以那种动画展现),它最后最后会调用,defaultActionForKey:这个应该就是隐式动画效果

很显然,UIView做了layer的代理,再UIView内部实行了-actionForKey:方法,估计如果不是调用UIView的动画方法时,实现的协议方法actionForKey:里面返回一个nil,如果调用UIView的自己的动画方法,就返回值,产生了动画。

上面也可以总结一点:UIKit建立在Core Animation(默认对所有东西都做动画)之上,所有Core Animation的动画方法,再UIKit层都有对应的。
比如:

1、UIView有两个方法,+beginAnimations:context:和+commitAnimations,和CATransaction的+begin和+commit方法类似。
2、 UIView的block的动画允许你在动画结束的时候提供一个完成的动作。CATranscation接口提供的+setCompletionBlock:方法也有同样的功能。

在上面讲系统大概是如何实现隐式动画,说到”没有代理对象,去找图层动画的action(以那种动画展现)”,如果我不想用系统提供的动画效果,有没有其他的动画效果可以执行。

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@property (nonatomic, weak) IBOutlet CALayer *colorLayer;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    //create sublayer    self.colorLayer = [CALayer layer];    self.colorLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);    self.colorLayer.backgroundColor = [UIColor blueColor].CGColor;    //add a custom action    CATransition *transition = [CATransition animation];    transition.type = kCATransitionPush;    transition.subtype = kCATransitionFromLeft;    self.colorLayer.actions = @{@"backgroundColor": transition};    //add it to our view    [self.layerView.layer addSublayer:self.colorLayer];}@end

上面就做到了自定义action(动画效果)。

注意:这里要提醒大家:CATransition和CATransaction的区别。

这个就能看出CATransition和CATransaction真正的区别了吧。
只要记住后面单词的区别:

  1. action结尾的就是开始动画、提交动画(action行为的事情)
  2. sition结尾的就是名词,就是自定义动画相关的属性,
1 0