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..
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 orCAAnimation
Groups and as each animation finishes it will call ananimationDidStop:finished:
delegate method (note that animations that are part of a group won't call their delegate'sanimationDidStop:finished:
method.I figured out a cool trick that makes using the
CAAnimation animationDidStop:finished:
method more powerful. I use the methodsetValue:forKey:
to add a block of code to a stand-alone animation or animation group, with the key @"animationCompletionBlock". I then write a generalanimationDidStop: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
block, as you suggested. When you do that, you can using the
CATransaction
class methodsetCompletionBlock:
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.I don't believe you can "nest" CA animations as you have in your example.
You need to specify a delegate for the animation and put your second "transition" within the
animationDidStop:finished:
selector of the delegate.Might want to have a look at Apple's Animation Types & Timing Programming Guide.
I pull this off using the
setCompletionBlock
method to define a closure that triggers the next animation when the first one is finished:Without including all the "tricks" up my "toolchain", this example isn't directly copy/pastable… but it does show a REALLY easy strategy for "chained" animations..
This obviously depends on some "external magic", but the concept is simple, and eliminates (through dependencies) the need to "deal with" ANY sort of gross delegation. In particular, the
animate:from:to:time:easing:completion
, etc. categories come from the great FunSize Framework, on Github.You can also use animation grouping and use the beginTime field of the animation. Try something like this:
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.
What I have always preferred to setting the begin and end time of each animation seperately is this:
I used A2DynamicDelegate (whose development is now happening in the BlocksKit-Repo, who knows why <_<) to implement a completionBlock property in a Category on CAAnimation.
This enabled me to do stuff like this:
Much more flexible :)
I've uploaded my code for completion handler here. Have a look at the notice in the header file though. I am really confused why the method isn't called.