iOS UI相关

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

2019-08-09  本文已影响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>>,我只是一个爱读书的程序员,好的东西分享出来,书中的内容总结出来加深理解。

上一篇下一篇

猜你喜欢

热点阅读