当你改变`CALayer`的一个可做动画的属性,它并不能立刻在屏幕上体现出来。相反,它是从先前的值平滑过渡到新的值。这一切都是默认的行为,你不需要做额外的操作。---- 隐式动画
当你改变一个属性,Core Animation是如何判断动画类型和持续时间的呢?实际上动画执行的时间取决于当前*事务*的设置,动画类型取决于*图层行为*。
事务实际上是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:`方法来修改动画时间的时候可能会影响此时刻别的动画,所以我们应该在调整动画之前压入一个新的事务。
示例:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
// 开启一个新的事务
[CATransaction begin];
// 设置动画的持续时间
[CATransaction setAnimationDuration:3.0];
// 随机颜色
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;
// 提交动画
[CATransaction commit];
}
UIView的动画也是使用了“事务”,`CATransaction`的`+begin`和`+commit`方法在`+animateWithDuration:animations:`内部自动调用,这样block中所有属性的改变都会被事务所包含。这样也可以避免开发者由于对`+begin`和`+commit`匹配的失误造成的风险。
基于`UIView`的block的动画允许你在动画结束的时候提供一个完成的动作。`CATranscation`接口提供的`+setCompletionBlock:`方法也有同样的功能。要注意的是:完成的动作执行的快得多,这是因为完成块是在block中事务提交并出栈之后才被执行,既完成动作用的是默认的事务做变换,默认的时间也就变成了0.25秒。