IOS 开发- 隐式动画

Do What I mean, not what I say

Implicit Animations

首先看一个demo

@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]
}
@end

在这个程序中,我们并没有看到任何代码和动画相关。我们只是单纯的更改了一个非UIView关联的Layer的属性(一定要是非UIView相关联的Layer,后文会解释原因)。当我们改变一个属性时,Core Animation是怎么判断动画类型和持续时间呢?实际上动画执行的时间取决于当前事务(Transaction)的设置,动画类型取决于图层行为(Layer Action)。事务实际上是Core Animation用来包含一系列动画集合的机制,任何时候在一个指定事务中去改变都不会立刻发生变化,而是当事务提交的时候开始用一个动画过渡到新值。事务是通过CATransation 类来管理的,这个类的设计很有意思,不像它的名字,它管理了一个你不能直接访问的事务的栈。CATransaction没有属性或者实例方法,并且也不能使用alloc,init来创建。然而,你可以通过类方法,+begin和+commit来把一个新的事务压入栈中,或者推出当前事件。

任何的一个可动画的图层的属性的变化都会被添加到栈顶的事务。(Any layer property change that can be animated will be added to the topmost transaction in the stack.)你可以通过+setAnimationDuration: 方法来设置当前事务的动画时间,或者,通过+animationDuration 方法来获取当前的动画时间。

Core Animation 在每一个run loop周期中自动开始一个新的事务,即是你不显示的使用[CATransaction begin]开始一个新的事务,任何一次在run loop循环中属性的改变都会被集中起来,然后坐一次0.25秒的动画。明白了这些之后,我们就可以轻松的修改变色动画的时间了,我们当然可以使用当前事务的+setAnimationDuration:方法来修改动画持续时间,但是我们先起一个新的事务,这样的话修改时间就不会产生副作用,因为修改当前事务的时间可能会影响统一时刻的其他动画,所以最好还是在调整动画之前压入一个新的事务。

- (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
    //commit the transaction
    [CATransaction commit]; 
}

完成块
基于UIView的block动画允许你在动画结束的时候提供一个完成块。CATransaction接口提供的+setCompleteBlock:方法也有同样的功能。

- (IBAction)changeColor {
    //begin a new transaction
    [CATransaction begin];
    //set the animation duration to 1 second
    [CATransaction setAnimationDuration:1.0]; //add the spin animation on completion
    [CATransaction setCompletionBlock:^{
    //rotate the layer 90 degrees
    CGAffineTransform transform = self.colorLayer.affineTransform; 
    transform = CGAffineTransformRotate(transform, M_PI_2); 
    self.colorLayer.affineTransform = transform;
}];

    //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]; 
}

注意,旋转动画要比颜色渐变快得多,这事因为完成块是在颜色渐变得事务提交并出栈之后才被执行,所以,用默认的事务做变换,默认的时间也变成了0.25秒。

你可能感兴趣的:(IOS 开发- 隐式动画)