Re: CA: How to wait for an animation to finish?
Re: CA: How to wait for an animation to finish?
- Subject: Re: CA: How to wait for an animation to finish?
- From: John Harper <email@hidden>
- Date: Sun, 16 Mar 2008 12:07:31 -0700
On Mar 16, 2008, at 9:03 AM, Jens Alfke wrote:
One thing I still haven't figured out how to do in Core Animation is
how to schedule an animation to start after previous animations have
finished. Anyone know how?
If you're using implicit animations, the best way currently is via
NSObject's -performSelector:withObject:afterDelay: methods. Or disable
the implicitly added animations and create the objects by hand, you
can then either use the delegate callbacks, or just schedule them to
happen at the right time via the beginTime properties
The docs imply that [CATransaction flush] ought to block till the
previous transaction has completed, but I can't get it to do
anything. The only workaround I've found has been the very ugly one
of calling usleep(0.25e6) to wait for step 2 to finish.
That's not what the comment/documentation is supposed to imply, but I
can see why you might read it that way, the header file says:
/* Commits any extant implicit transaction. Will delay the actual commit
* until any nested explicit transactions have completed. */
+ (void)flush;
what the second sentence is trying to get across is that if you do
something like this:
[CATransaction begin];
…
[CATransaction flush];
…
[CATransaction commit];
the actual flush to the render tree is delayed until after the
outermost commit.
It seems that the expected way to sequence animations is to create a
CAAnimation; that way I can be called when it completes, or even add
key-frames. The problem with this is that it requires that all the
layer property changes be done using a completely different API:
instead of setting layer's property directly, as I do now, I have to
create a CAAnimation object, set its parameters, and add it to the
layer. That means that the lower-level code I have that manipulates
the layers directly can't be used, and has to be duplicated using
this different API. There's got to be a better way!
Implicit animations are useful in many scenarios, but due to the
simplicity of the API they don't cover everything. If there are things
you'd like to see them extended to support please file bugs.
[later message]
After some experimenting I found that setting the "position"
property of a layer sets an animation for the "position" key; so you
can retrieve it by calling [layer animationForKey: @"position"]. But
that's an undocumented implementation detail that could change in
the future,
this should be documented, you can rely on it (see below)
so I don't want to rely on it. (There is no "animations" property
that would let me get all the current animations on the layer.)
Worse, the CAAnimation retrieved from that key has somehow been made
read-only, so attempting to set its delegate (so I can be informed
when it finishes) throws an exception.
Yes, once an animation has been copied and added to the layer it's
currently made immutable since we have no way to propagate changes
into the render tree (it's possible this could change in a future
release)
The relationship between implicit and explicit animations seems very
confusing, and I can't find any documentation of it. I'm fighting my
way through this by trial and error...
There's no difference between an implicit animation and an explicit
animation. The only difference is that implicit animations are created
by the layer's -actionForKey: method in response to a property being
changed, while explicit animations are created by your code directly.
This is what happens when a layer property is modified:
1. Finds the "action" object associated with the property. If the
disableActions transaction property is true the action is nil,
otherwise, calls the -actionForKey: method, with the key being the key-
path of the property being changed. -actionForKey: does these things
to try to find a non-nil object: (the first that returns non-nil stops
the others from being tried)
1. calls the -actionForLayer:forKey: delegate method
2. looks in the layer's "actions" property (a dictionary)
3. walks up the "style" hierarchy looking in the "actions" property
of each style dictionary
4. calls the +defaultActionForKey: method.
5. if the key represents an animatable property, creates an animation
object to represent that animation.
any of these steps can return [NSNull null] to stop the search.
2. Calls the -willChangeValueForKey: method
3. Sets the property to its new value wherever that's stored
4. Calls the -didChangeValueForKey: method
5. If the action from step (1) is non-nil, invoke it's -
runActionForKey:object:arguments: method. In the case of CAAnimation,
this invokes the layer's -addAnimation:forKey: method to add the
animation to the layer (the key is the key-path of the changed
property.)
Hopefully that makes it clearer, the important thing is that an
implicit animation is just an explicit animation that was created
within a property setter via the -actionForKey: mechanism,
John
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden