When exactly do implicit animations take place in iOS? - ios

Everyone and every book claims that there are implicit animations happening in CALayer. However, every time I wanted to verify that so far, I end up with a hard-snap to the set value. No animation at all.
Here's an example in a project where nothing else is happening. All I do is create a view, then get it's CALayer instance and do something that should be implicitly animated.
[theLayer setValue:[NSNumber numberWithFloat:M_PI * 1.1] forKeyPath:#"transform.rotation.z"];
Another one:
CGRect currentBounds = theLayer.bounds;
currentBounds.size.width += 120.f;
[self.animatedLayer setBounds:currentBounds];
The view contains some stuff of course so I can see the change.
I see the visual change, but as a hard snap. No animation at all.
So either all those books are wrong and have old Mac OS X knowledge in mind when writing about Core Animation and implicit animations, or I'm doing something wrong. Can anyone provide an working example that demonstrates implicit animations on the iPhone?

UIKit disables implicit animations. To be more specific, a CALayer associated with a UIView will never implicitly animate. CALayers that you create yourself and that are not associated with a UIView will buy into the normal implicit animation machinery.
If you're interested in how this works, implicit animations happen after the normal -actionForKey: lookup. If there's a CAAction for a given property, it's used. Otherwise, the implicit animation is used. In the case of a CALayer associated with a UIView, UIView implements the -actionForLayer:forKey: delegate method, and when not in a UIView animation block it always returns [NSNull null] to signify that the action lookup should stop here. This prevents implicit animations from working. Inside of a UIView animation block, it constructs its own action to represent the current UIView animation settings. Again, this prevents implicit animations.
If you need to animate CALayer properties that UIView won't do for you, you can use an explicit CAAnimation subclass (such as CABasicAnimation).

Old post, but link below points to a section in the Core Animation Programming Guide that helps shed some more light on what Kevin Ballard was saying. There really needs to be a blatant note that mentions that in order to animate a UIView's underlying layer properties you need to ensure that you set the layer's delegate to an instance that will adopt the "actionForLayer:ForKey:" method and return nil. It's been found that you can also set the delegate to an instance that doesn't adopt this method and it still allows implicit animations, but this is a sloppy and confusing practice.
Core Animation - Layer Actions - Defined Search Pattern for Action Keys

Keep in mind that sublayers of a UIView's primary layer do not normally have the UIView as their delegate. Therefore, they participate in implicit animation unless you explicitly block this, even if you haven't provided a delegate to return a nil action in response to actionForLayer:forKey:.
So, one simple way to get implicit animation in a generic view is simply to add a sublayer that covers the primary layer.
Matt Neuberg's book Programming iOS 5 (currently in beta on Safari Books Online) explains this topic very lucidly.

It's exactly correct of Kevin Ballard's answer. I want to provide something more here.
The detail information from the official document
There is a section called: Rules for Modifying Layers in iOS, and you will find
The UIView class disables layer animations by default but reenables them inside animation blocks.
Except enable the implicit in the UIView animation block. There are two another solution:
Make the layer you need animation a sublayer of a view. Refer to the [answer][2]
[2]: Implicit property animations do not work with CAReplicatorLayer? of Implicit animation fade-in is not working. I tried this, it worked as expected.
assign the layer's delegate to the layer itself. The default delegate of the layer in iOS is its backing store view which implements the actionForLayer:(id)layer forKey:(NSString *)key and return [NSNull null] to disable the implicit animation of the layer.

You could also set the layer's delegate to your own object and handle -actionForLayer:forKey:. Seems as if you get implicit animation even if the delegate doesn't implement -actionForLayer:forKey:.

actually, you could just return nil to get the default animation of CALay.
(id)actionForLayer:(CALayer *)layer forKey:(NSString *)event{
return nil;
}

Related

how is UIView. Animate (withduration:) implemented? [duplicate]

Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods. In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations. I guess it does not do a snapshot of whole view hierarchy, as that would be horribly inefficient. The animation block is opaque code blob during runtime, so I don't think it can analyze that directly. Does it replace the implementation of property setters on CALayer with some kind of recoding versions? Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
It is actually a very elegant solution that is built around the fact that the view is the layers delegate and that stand-alone layers implicitly do animate on property changes.
It just happens to be that I gave a BLITZ talk about this at NSConference just a couple of days ago and I posted my slides on GitHub and tried to write down more or less what I said in the presenter notes.
That said: it is a very interesting question that I don't see being asked very often. It may be a bit to broad but I really like curiosity.
UIView animations existed before iOS 4
Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods.
UIView animations existed before iOS 4 but in a different style (that is no longer recommended to use because it is more cumbersome to use). For example, animating position and color of a view with a delay could be done like this. Disclaimer: I did not run this code so it may contains bugs.
// Setup
static void *myAnimationContext = &myAnimationContext;
[UIView beginAnimations:#"My Animation ID" context:myAnimationContext];
// Configure
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelay:0.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// Make changes
myView.center = newCenter;
myView.backgroundColor = newColor;
// Commit
[UIView commitAnimations];
The view-layer synergy is very elegant
In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
It is actually the other way around. The view is built on top of the layer and they work together very closely. When you set a property on the view it sets the corresponding property on the layer. You can for example see that the view doesn't even have it's own variable for the frame, bounds or position.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations.
It does not need to do that and this is where it all gets very elegant. Whenever a layer property changes, the layer looks for the action (a more general term for an animation) to execute. Since setting most properties on a view actually sets the property on the layer, you are implicitly setting a bunch of layer properties.
The first place that the layer goes looking for an action is that it asks the layer delegate (it is documented behaviour that the view is the layers delegate). This means that when the layer property changes, the layers asks the view to provide an animation object for that each property change. So the view doesn't need to keep track of any state since the layer has the state and the layer asks the view to provide an animation when the properties change.
Actually, that's not entirely true. The view needs to keep track of some state such as: if you are inside of the block or not, what duration to use for the animation, etc.
You could imagine that the API looks something like this.
Note: I don't know what the actual implementation does and this is obviously a huge simplification to prove a point
// static variables since this is a class method
static NSTimeInterval _durationToUseWhenAsked;
static BOOL _isInsideAnimationBlock;
// Oversimplified example implementation of how it _could_ be done
+ (void)animateWithDuration:(NSTimeInterval)duration
animations:(void (^)(void))animations
{
_durationToUseWhenAsked = duration;
_isInsideAnimationBlock = YES;
animations();
_isInsideAnimationBlock = NO;
}
// Running the animations block is going to change a bunch of properties
// which result in the delegate method being called for each property change
- (id<CAAction>)actionForLayer:(CALayer *)layer
forKey:(NSString *)event
{
// Don't animate outside of an animation block
if (!_isInsideAnimationBlock)
return (id)[NSNull null]; // return NSNull to don't animate
// Only animate certain properties
if (![[[self class] arrayOfPropertiesThatSupportAnimations] containsObject:event])
return (id)[NSNull null]; // return NSNull to don't animate
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:event];
theAnimation.duration = _durationToUseWhenAsked;
// Get the value that is currently seen on screen
id oldValue = [[layer presentationLayer] valueForKeyPath:event];
theAnimation.fromValue = oldValue;
// Only setting the from value means animating form that value to the model value
return theAnimation;
}
Does it replace the implementation of property setters on CALayer with some kind of recoding versions?
No (see above)
Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
Yes, sort of (see above)
Creating similar API yourself
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
You can definitely create a similar block based API if you want to provide your own animations based on property changes. If you look at the techniques I showed in my talk at NSConference for inspecting UIView animations (directly asking the layer for the actionForLayer:forKey: and using layerClass to create a layer that logs all addAnimation:forKey: information) then you should be able to learn enough about how the view is using the layer to create this abstraction.
I'm not sure if recording state changes is you end goal or not. If you only want to do your own animation API then you shouldn't have to. If you really want to do it, You could probably could, but there wouldn't be as much communication infrastructure (delegate methods and callbacks between the view and the layer) available to you as there is for animations.
David's answer is awesome. You should accept it as the definitive answer.
I do have a minor contribution. I created a markdown file in one of my github projects called "Sleuthing UIView Animations." (link) It goes into more detail on how you can watch the CAAnimation objects that the system creates in response to UIView animations. The project is called KeyframeViewAnimations. (link)
It also shows working code that logs the CAAnimations that are created when you submit UIView animations.
And, to give credit where credit is due, it was David who suggested the technique I use.

How can a CALayer delegate trigger display updates (during animations) for a custom property?

CALayer seems to have almost everything required to add properties to a layer at runtime, without subclassing, using a delegate and/or the layer's actions property. However, one thing I have not figured out is how to trigger display updates when one of these dynamic properties changes in an animation.
I know how do this in a custom subclass of CALayer: simply define the properties in the subclass, mark them #dynamic, and override needsDisplayForKey: and return YES for the custom properties. Then display will be invoked during animations, which, by default, will even trigger a call to the layer delegate's drawLayer:inContent: method, if present (though it's of questionable usefulness, given that you've already got this subclass where you can implement drawInContext:). However, I am trying to see if this is possible without subclassing CALayer.
I can get as far as supporting updates outside of animations using only a layer delegate, by installing a CAAction in the layer's actions property, or implementing actionForLayer:forKey: in the layer delegate, and having that action send a setNeedsDisplay message to the layer. However, actionForKey: is apparently not called during an animation (makes sense, since it is used to trigger implicit animations), and there is no equivalent to needsDisplayForKey: in the layer delegate protocol, that I can see.
So, is there any way to tell CALayer to call display for custom properties besides the above? Or is it not possible to implement animatable custom layer properties in a layer delegate alone? It seems like Apple would prefer one to use delegation when possible, but without a way to refresh the layer contents during an animation, the delegate interface is incomplete. Any suggestions?

Internal implementation of UIView's block-based animation methods

Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods. In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations. I guess it does not do a snapshot of whole view hierarchy, as that would be horribly inefficient. The animation block is opaque code blob during runtime, so I don't think it can analyze that directly. Does it replace the implementation of property setters on CALayer with some kind of recoding versions? Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
It is actually a very elegant solution that is built around the fact that the view is the layers delegate and that stand-alone layers implicitly do animate on property changes.
It just happens to be that I gave a BLITZ talk about this at NSConference just a couple of days ago and I posted my slides on GitHub and tried to write down more or less what I said in the presenter notes.
That said: it is a very interesting question that I don't see being asked very often. It may be a bit to broad but I really like curiosity.
UIView animations existed before iOS 4
Ever since their introduction in iOS 4, I have been wondering about the internal implementation of the UIView's block-based animation methods.
UIView animations existed before iOS 4 but in a different style (that is no longer recommended to use because it is more cumbersome to use). For example, animating position and color of a view with a delay could be done like this. Disclaimer: I did not run this code so it may contains bugs.
// Setup
static void *myAnimationContext = &myAnimationContext;
[UIView beginAnimations:#"My Animation ID" context:myAnimationContext];
// Configure
[UIView setAnimationDuration:1.0];
[UIView setAnimationDelay:0.25];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
// Make changes
myView.center = newCenter;
myView.backgroundColor = newColor;
// Commit
[UIView commitAnimations];
The view-layer synergy is very elegant
In particular I would like to understand what mystical features of Objective C are used there to capture all the relevant layer state changes before and after execution of the animation block.
It is actually the other way around. The view is built on top of the layer and they work together very closely. When you set a property on the view it sets the corresponding property on the layer. You can for example see that the view doesn't even have it's own variable for the frame, bounds or position.
Observing the black-box implementation, I gather that it needs to capture the before-state of all layer properties modified in the animation block, to create all the relevant CAAnimations.
It does not need to do that and this is where it all gets very elegant. Whenever a layer property changes, the layer looks for the action (a more general term for an animation) to execute. Since setting most properties on a view actually sets the property on the layer, you are implicitly setting a bunch of layer properties.
The first place that the layer goes looking for an action is that it asks the layer delegate (it is documented behaviour that the view is the layers delegate). This means that when the layer property changes, the layers asks the view to provide an animation object for that each property change. So the view doesn't need to keep track of any state since the layer has the state and the layer asks the view to provide an animation when the properties change.
Actually, that's not entirely true. The view needs to keep track of some state such as: if you are inside of the block or not, what duration to use for the animation, etc.
You could imagine that the API looks something like this.
Note: I don't know what the actual implementation does and this is obviously a huge simplification to prove a point
// static variables since this is a class method
static NSTimeInterval _durationToUseWhenAsked;
static BOOL _isInsideAnimationBlock;
// Oversimplified example implementation of how it _could_ be done
+ (void)animateWithDuration:(NSTimeInterval)duration
animations:(void (^)(void))animations
{
_durationToUseWhenAsked = duration;
_isInsideAnimationBlock = YES;
animations();
_isInsideAnimationBlock = NO;
}
// Running the animations block is going to change a bunch of properties
// which result in the delegate method being called for each property change
- (id<CAAction>)actionForLayer:(CALayer *)layer
forKey:(NSString *)event
{
// Don't animate outside of an animation block
if (!_isInsideAnimationBlock)
return (id)[NSNull null]; // return NSNull to don't animate
// Only animate certain properties
if (![[[self class] arrayOfPropertiesThatSupportAnimations] containsObject:event])
return (id)[NSNull null]; // return NSNull to don't animate
CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:event];
theAnimation.duration = _durationToUseWhenAsked;
// Get the value that is currently seen on screen
id oldValue = [[layer presentationLayer] valueForKeyPath:event];
theAnimation.fromValue = oldValue;
// Only setting the from value means animating form that value to the model value
return theAnimation;
}
Does it replace the implementation of property setters on CALayer with some kind of recoding versions?
No (see above)
Or is the support for this property change recoding baked-in somewhere deep inside the CALayers?
Yes, sort of (see above)
Creating similar API yourself
To generalize the question a little bit, is it possible do create similar block-based API for recording state changes using some Objective C dark magic, or does this rely on knowing and having the access to the internals of the objects being changed in the block?
You can definitely create a similar block based API if you want to provide your own animations based on property changes. If you look at the techniques I showed in my talk at NSConference for inspecting UIView animations (directly asking the layer for the actionForLayer:forKey: and using layerClass to create a layer that logs all addAnimation:forKey: information) then you should be able to learn enough about how the view is using the layer to create this abstraction.
I'm not sure if recording state changes is you end goal or not. If you only want to do your own animation API then you shouldn't have to. If you really want to do it, You could probably could, but there wouldn't be as much communication infrastructure (delegate methods and callbacks between the view and the layer) available to you as there is for animations.
David's answer is awesome. You should accept it as the definitive answer.
I do have a minor contribution. I created a markdown file in one of my github projects called "Sleuthing UIView Animations." (link) It goes into more detail on how you can watch the CAAnimation objects that the system creates in response to UIView animations. The project is called KeyframeViewAnimations. (link)
It also shows working code that logs the CAAnimations that are created when you submit UIView animations.
And, to give credit where credit is due, it was David who suggested the technique I use.

What is the purpose of the "forKey" parameter when adding a CAAnimation to a layer?

I am very new to iOS programming, Objective-C, and programming in general, so please excuse me if you find this question frustratingly simple-minded.
The docs on Apple's website are usually great, but I'm having some trouble trying to wrap my head around certain parts of Core Animation. I want to explicitly animate the position of a CALayer. From what I understand, I need to create a CABasicAnimation object, configure it with fromValue, toValue, etc., then add it to a layer using this method:
- (void)addAnimation:(CAAnimation *)anim forKey:(NSString *)key
My problem is that I have no idea what the significance of the forKey: parameter is. From what I've seen in examples online, it's not required? I suppose it has something to do with key-value coding? (I still don't really understand that, either.) Even if it's not required, I'd like to know what it is so that I can take advantage of its usefulness in my app.
Thanks for any help you can offer.
It allows you to override animations. For example, implicit animations created by mutating an implicitly animateable property (such as opacity) will use the name of the property as a key. This way if you modify it again (to produce a new animation), the new animation will replace the old one instead of trying to have both animations running simultaneously.
CALayer has several methods for getting the animations that have been added to the layer. If you want to get, replace, or remove a particular animation from CALayer you have to give it the key when you call animationForKey: or removeAnimationForKey:.
You don't have to provide a key, you can use nil for the key if you don't have any particular need to find a particular animation by key.
It's just some identifier for your animation. You can call animationForKey: and removeAnimationForKey: methods later with the specified key.
Also because layer may have only one animation per unique key, you can use this value as identifier for some type of animations and all ...ForKey: methods will return/remove/replace most current animation for a given animation type/key.

How can I determine if an animation is currently playing in UIView?

I'd like to determine if a UITableView and other views are currently performing some type of animation with core animation.
In investigating this, I discovered the following Stack Overflow question & answer:
how to tell if uiview is in middle of animation?
I've verified that this technique of checking the animationKeys property works great for controls like UISlider, however when attempting to check for animationKeys during a UITableView animation, the NSArray count is always 0. I even went so far as to recursively check every view and layer in the view hierarchy for animationKeys, and all of them had a count of 0.
In looking into the addAnimation:forKey: selector of CALayer, I discovered that it's possible to add an animation with a nil key. This is probably the reason animationKeys has a count of 0. Due to this, I can't use the above linked technique.
The question: Is it even possible to reliably determine if an animation is currently playing? If so, what are some techniques for determining this?
I would use the delegate methodanimationDidStart:
Delegate Methods
animationDidStart: Called when the animation begins its active
duration.
(void)animationDidStart:(CAAnimation *)theAnimation Parameters theAnimation The CAAnimation instance that started animating.
Availability Available in iOS 2.0 and later. Declared In CAAnimation.h
Alternatively, you could query thepresentationLayerand compare it to the model layer. For example:
CGPoint presentationPosition = myLayer.presentationLayer.position;
CGPoint modelPosition = myLayer.position;
BOOL animationInProgress = NO;
if (presentationPosition.x != modelPosition.x ||
presentationPosition.y != modelPosition.y)
{
animationInProgress = YES;
}

Resources