按照个人意思去作,而不是我说的。 -- 埃德娜,辛普森 git
咱们在第一部分讨论了Core Animation除了动画以外能够作到的任何事情。可是动画是Core Animation库一个很是显著的特性。这一章咱们来看看它是怎么作到的。具体来讲,咱们先来讨论框架自动完成的隐式动画(除非你明确禁用了这个功能)。 github
Core Animation基于一个假设,说屏幕上的任何东西均可以(或者可能)作动画。动画并不须要你在Core Animation中手动打开,相反须要明确地关闭,不然他会一直存在。 网络
当你改变 CALayer 的一个可作动画的属性,它并不能马上在屏幕上体现出来。相反,它是从先前的值平滑过渡到新的值。这一切都是默认的行为,你不须要作额外的操做。 框架
这看起来这太棒了,彷佛不太真实,咱们来用一个demo解释一下:首先和第一章“图层树”同样建立一个蓝色的方块,而后添加一个按钮,随机改变它的颜色。代码见清单7.1。点击按钮,你会发现图层的颜色平滑过渡到一个新值,而不是跳变(图7.1)。 dom
清单7.1 随机改变图层颜色 oop
@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 it to our view [self.layerView.layer addSublayer:self.colorLayer]; } - (IBAction)changeColor { //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;  } @end
图7.1 添加一个按钮来控制图层颜色 动画
这其实就是所谓的隐式动画。之因此叫隐式是由于咱们并无指定任何动画的类型。咱们仅仅改变了一个属性,而后Core Animation来决定如何而且什么时候去作动画。Core Animaiton一样支持显式动画,下章详细说明。 atom
但当你改变一个属性,Core Animation是如何判断动画类型和持续时间的呢?实际上动画执行的时间取决于当前事务的设置,动画类型取决于图层行为。 spa
事务其实是Core Animation用来包含一系列属性动画集合的机制,任何用指定事务去改变能够作动画的图层属性都不会马上发生变化,而是当事务一旦提交的时候开始用一个动画过渡到新值。 设计
事务是经过 CATransaction 类来作管理,这个类的设计有些奇怪,不像你从它的命名预期的那样去管理一个简单的事务,而是管理了一叠你不能访问的事务。CATransaction没有属性或者实例方法,而且也不能用+alloc和-init方法建立它。可是能够用 +begin 和 +commit 分别来入栈或者出栈。
任何能够作动画的图层属性都会被添加到栈顶的事务,你能够经过 +setAnimationDuration: 方法设置当前事务的动画时间,或者经过 +animationDuration 方法来获取值(默认0.25秒)。
Core Animation在每一个run loop周期中自动开始一次新的事务(run loop是iOS负责收集用户输入,处理定时器或者网络事件而且从新绘制屏幕的东西),即便你不显式的用[CATransaction begin]开始一次事务,任何在一次run loop循环中属性的改变都会被集中起来,而后作一次0.25秒的动画。
明白这些以后,咱们就能够轻松修改变色动画的时间了。咱们固然能够用当前事务的+setAnimationDuration:方法来修改动画时间,但在这里咱们首先起一个新的事务,因而修改时间就不会有别的反作用。由于修改当前事务的时间可能会致使同一时刻别的动画(如屏幕旋转),因此最好仍是在调整动画以前压入一个新的事务。
修改后的代码见清单7.2。运行程序,你会发现色块颜色比以前变得更慢了。
清单7.2 使用CATransaction控制动画时间
- (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]; }
若是你用过UIView的动画方法作过一些动画效果,那么应该对这个模式不陌生。UIView有两个方法,+beginAnimations:context:和+commitAnimations,和CATransaction的+begin和+commit方法相似。实际上在 +beginAnimations:context: 和 +commitAnimations 之间全部视图或者图层属性的改变而作的动画都是因为设置了CATransaction的缘由。
在iOS4中,苹果对UIView添加了一种基于block的动画方法: +animateWithDuration:animations: 。这样写对作一堆的属性动画在语法上会更加简单,但实质上它们都是在作一样的事情。
CATransaction的+begin和+commit方法在+animateWithDuration:animations:内部自动调用,这样block中全部属性的改变都会被事务所包含。这样也能够避免开发者因为对+begin和+commit匹配的失误形成的风险。