Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining Core Animation animations

Which is the most elegant and modular way to chain animation in a Core Animation context?

I mean to do animations that starts just when other finished (for example, changing position and then opacity).. normal approach is to directly change properties:

layer.position = new_point;
layer.opacity = 0.0f;

but this will do them at the same time. I want to make one wait for the other.

And what about chaining animations for different objects? I've read about CATransaction used like:

[CATransaction begin]
layer1.property = new_property;
[CATransaction begin]
layer2.property2 = new_property2;
[CATransaction commit];
[CATransaction commit];

but it doesn't seem to work..

like image 469
Jack Avatar asked Dec 15 '09 16:12

Jack


3 Answers

You can also use animation grouping and use the beginTime field of the animation. Try something like this:

CABasicAnimation *posAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
[posAnimation setFromValue:[NSNumber numberWithFloat:0.0]];
[posAnimation setToValue:[NSNumber numberWithFloat:1.0]];
// Here's the important part
[posAnimation setDuration:10.0];
[posAnimation setBeginTime:0.0];

CABasicAnimation *borderWidthAnimation = [CABasicAnimation animationWithKeyPath:@"borderWidth"];
[borderWidthAnimation setFromValue:[NSNumber numberWithFloat:0.0]];
[borderWidthAnimation setToValue:[NSNumber numberWithFloat:1.0]];
// Here's the important part
[borderWidthAnimation setDuration:10.0];
[borderWidthAnimation setBeginTime:5.0];

CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:10.0];
[group setAnimations:[NSArray arrayWithObjects:posAnimation, borderWidthAnimation, nil]];

[layer addAnimation:group forKey:nil];

Notice that the duration of the entire animation is 10 seconds. The first one starts at second 0 and the second one starts at 5 seconds.

like image 71
Matt Long Avatar answered Nov 16 '22 15:11

Matt Long


As Matt pointed out, you can create animation groups that consist of different animations for the same layer with different begin times. You can also set a delegate for stand-alone CAAnimation objects or CAAnimation Groups and as each animation finishes it will call an animationDidStop:finished: delegate method (note that animations that are part of a group won't call their delegate's animationDidStop:finished: method.

I figured out a cool trick that makes using the CAAnimation animationDidStop:finished: method more powerful. I use the method setValue:forKey: to add a block of code to a stand-alone animation or animation group, with the key @"animationCompletionBlock". I then write a general animationDidStop:finished: method that checks the just-completed animation for a @"animationCompletionBlock" key, and if it finds it, execute the block of code there.

Take a look at this project on github for a working example of that technique:

CAAnimation demo with completion blocks

You an also Set a group of animations inside a

[CATransaction begin];
//...
[[CATransaction commit];

block, as you suggested. When you do that, you can using the CATransaction class method setCompletionBlock: to invoke a block of code when all the animations in the current transaction group complete. The completion block for one transaction can then trigger the next transaction.

like image 36
Duncan C Avatar answered Nov 16 '22 16:11

Duncan C


I pull this off using the setCompletionBlock method to define a closure that triggers the next animation when the first one is finished:

[CATransaction begin]
layer1.property = new_property;
CATransaction.setCompletionBlock {
    [CATransaction begin]
    layer2.property2 = new_property2;
    [CATransaction commit];
}
[CATransaction commit];
like image 2
wcochran Avatar answered Nov 16 '22 15:11

wcochran