美文网首页iOS UI相关
UIView关联的图层是如何禁用了隐式动画

UIView关联的图层是如何禁用了隐式动画

作者: 某非著名程序员 | 来源:发表于2019-08-09 21:54 被阅读0次

      当你改变 CALayer 的一个可做动画的属性,它并不能立刻在屏幕上体现出来。相反,它是从先前的值平滑过渡到新的值。这一切都是默认的行为,你不需要做额外的操作。这就是隐式动画。
      隐式动画是通过事务来管理的,事务实际上是Core Animation用来包含一系列属性动画集合的机制,任何用指定事务去改变可以做动画的图层属性都不会立刻发生变化,而是当事务一旦提交的时候开始用一个动画过渡到新值。事务是通过 CATransaction 类来做管理。
      试着直接对UIView的layer做动画:

    [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];
    

      你会发现动画并没有生效,隐式动画好像被 UIView 关联图层给禁用了。下面看看动画的调用步骤:
      当 CALayer 的属性被修改时候,它会调用 -actionForKey: 方法,传递属性的名称。剩下的操作都在 CALayer 的头文件中有详细的说明,实质上是如下几步:
    1.图层首先检测它是否有委托,并且是否实现 CALayerDelegate 协议指定的 -actionForLayer:forKey 方法。如果有,直接调用并返回结果。
    2.如果没有委托,或者委托没有实现 -actionForLayer:forKey 方法,图层接着检查包含属性名称对应行为映射的 actions 字典。
    3.如果 actions字典 没有包含对应的属性,那么图层接着在它的 style 字典接着搜索属性名。
    4.最后,如果在 style 里面也找不到对应的行为,那么图层将会直接调用定义了每个属性的标准行为的 -defaultActionForKey: 方法
      所以一轮完整的搜索结束之后, -actionForKey: 要么返回空(这种情况下将不会有动画发生),要么是 CAAction 协议对应的对象,最后 CALayer 拿这个结果去对先前和当前的值做动画。
      于是这就解释了UIKit是如何禁用隐式动画的:每个 UIView 对它关联的图层都扮演了一个委托,并且提供了 -actionForLayer:forKey 的实现方法。当不在一个动画块的实现中, UIView 对所有图层行为返回 nil ,但是在动画block范围之内,它就返回了一个非空值。

      可以用下面的代码验证下:

    @interface ViewController ()
    @property (nonatomic, weak) IBOutlet UIView *layerView;
    @end
    @implementation ViewController
    - (void)viewDidLoad
    {
    [super viewDidLoad];
    //test layer action when outside of animation block
    NSLog(@"Outside: %@", [self.layerView actionForLayer:self.layerView.layer forKey:@"backgroundColor"]);
    //begin animation block
    [UIView beginAnimations:nil context:nil];
    //test layer action when inside of animation block
    NSLog(@"Inside: %@", [self.layerView actionForLayer:self.layerView.layer forKey:@"backgroundColor"]);
    //end animation block
    [UIView commitAnimations];
    }
    @end
    

    结果:Outside: <null>,Inside: <CABasicAnimation: 0x757f090>
      于是我们可以预言,当属性在动画块之外发生改变, UIView 直接通过返回 nil 来禁用隐式动画。但如果在动画块范围之内,根据动画具体类型返回相应的属性,在这个例子就是 CABasicAnimation。
      当然返回 nil 并不是禁用隐式动画唯一的办法, CATransacition 有个方法叫做 +setDisableActions: ,可以用来对所有属性打开或者关闭隐式动画。
      总结一下,我们知道了如下几点:
    1.UIView 关联的图层禁用了隐式动画,对这种图层做动画的唯一办法就是使用 UIView 的动画函数(而不是依赖 CATransaction ),或者继承 UIView ,并覆盖 -actionForLayer:forKey: 方法,或者直接创建一个显式动画(具体细节见第八章)。
    2.对于单独存在的图层,我们可以通过实现图层的 -
    actionForLayer:forKey: 委托方法,或者提供一个 actions 字典来控制隐式动画。

    总结:文中内容摘自<<iOS CoreAnimation>>,我只是一个爱读书的程序员,好的东西分享出来,书中的内容总结出来加深理解。

    相关文章

      网友评论

        本文标题:UIView关联的图层是如何禁用了隐式动画

        本文链接:https://www.haomeiwen.com/subject/dpxcjctx.html