上一篇整理了 关于隐式动画的笔记
我们知道根 layer 是不能做隐式动画的
就像这样, 是没有动画效果的, 颜色瞬间就变化了
self.view.layer.backgroundColor = [UIColor blueColor].CGColor;
那么隐式动画是如何被禁用掉呢?
我们知道 Core Animation 通常对 CALayer 的所有可动画的属性做动画
但是 UIView 把它的根 layer 这个特性关闭了
为了更好说明这一点,我们需要知道隐式动画是如何实现的。
我们把改变属性时 CALayer 自动应用的动画称作行为
当 CALayer 的属性被修改时候,它会调用 -actionForKey:
方法,传递属性的名称
-actionForKey:
经过一波猛虎操作
流程如下
- 图层首先检测它是否有委托,并且是否实现 CALayerDelegate 协议指定的
-actionForLayer:forKey
方法
如果有,直接调用并返回结果。 - 如果没有委托,或者委托没有实现
-actionForLayer:forKey
方法
图层接着检查包含属性名称对应行为映射的 actions 字典。 - 如果 actions 字典没有包含对应的属性,那么图层接着在它的 style 字典接着搜索属性名
- 最后,如果在 style 里面也找不到对应的行为,那么图层将会直接调用定义了每个属性的标准行为的
-defaultActionForKey:
方法。
所以一轮完整的搜索结束之后,-actionForKey:
要么返回空(这种情况下将不会有动画发生)
要么是 CAAction 协议对应的对象,最后 CALayer 拿这个结果去对先前和当前的值做动画
于是这就解释了 UIView 是如何禁用根 Layer 隐式动画的:
每个 UIView 都成为了根 layer 的 delegate,并且提供了 -actionForLayer:forKey
的实现方法
当属性的改变不在一个事务中的时候返回值为空, 这种情况下将不会有动画发生
当属性的改变在一个事务中的时候返回值非空, 这时候就会有动画
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"Outside: %@", [self.layerView actionForLayer:self.layerView.layer forKey:@"backgroundColor"]);
// 开启一个事务
[UIView beginAnimations:nil context:nil];
NSLog(@"Inside: %@", [self.layerView actionForLayer:self.layerView.layer forKey:@"backgroundColor"]);
[UIView commitAnimations];
}
打印结果
$ LayerTest[21215:c07] Outside: <null>
$ LayerTest[21215:c07] Inside: <CABasicAnimation: 0x757f090>
于是我们知道
当属性在事务之外发生改变
UIView 直接通过返回nil来禁用隐式动画
但如果在事务范围之内
根据动画具体类型返回相应的属性
当然返回 nil 并不是禁用隐式动画唯一的办法
CATransacition 有个方法叫做 +setDisableActions:
可以用来对所有属性打开或者关闭隐式动画。如果在 [CATransaction begin]
之后添加下面的代码
同样也会阻止动画的发生:
[CATransaction setDisableActions:YES];
网友评论