Is there an easy way to be called back when a Core Animation reaches certain points as it's running (for example, at 50% and 66% of completion ?
I'm currently thinking about setting up an NSTimer, but that's not really as accurate as I'd like.
Is there an easy way to be called back when a Core Animation reaches certain points as it's running (for example, at 50% and 66% of completion ?
I'm currently thinking about setting up an NSTimer, but that's not really as accurate as I'd like.
If you don't want to hack a CALayer to report progress to you, there's another approach. Conceptually, you can use a CADisplayLink to guarantee a callback on each frame, and then simply measure the time that has passed since the start of the animation divided by the duration to figure out the percent complete.
The open source library INTUAnimationEngine packages this functionality up very cleanly into an API that looks almost exactly like the UIView block-based animation one:
All you need to do is call this method at the same time you start other animation(s), passing the same values for
duration
anddelay
, and then for each frame of the animation theanimations
block will be executed with the current percent complete. And if you want peace of mind that your timings are perfectly synchronized, you can drive your animations exclusively from INTUAnimationEngine.I've finally developed a solution for this problem.
Essentially I wish to be called back for every frame and do what I need to do.
There's no obvious way to observe the progress of an animation, however it is actually possible:
Firstly we need to create a new subclass of CALayer that has an animatable property called 'progress'.
We add the layer into our tree, and then create an animation that will drive the progress value from 0 to 1 over the duration of the animation.
Since our progress property can be animated, drawInContext is called on our sublass for every frame of an animation. This function doesn't need to redraw anything, however it can be used to call a delegate function :)
Here's the class interface:
And the implementation:
We can then add the layer to our main layer:
And animate it along with the other animations:
Finally, the delegate will be called back as the animation progresses:
I made a Swift (2.0) implementation of the CALayer subclass suggested by tarmes in the accepted answer: