Graphics Reference
In-Depth Information
If you run the project, you'll notice that the color snaps to its new value immediately when
the button is pressed instead of animating smoothly as before. What's going on? The
implicit animation seems to have been disabled for the
UIView
backing layer.
Come to think of it, we'd probably have noticed if
UIView
properties always animated
automatically whenever we modified them. So, if UIKit is built on top of Core Animation
(which always animates everything by default), how come implict animations are
disabled
by default in UIKit?
We know that Core Animation normally animates any property change of a
CALayer
(provided it
can
be animated) and that
UIView
somehow turns this behavior off for its
backing layer. To understand how it does that, we need to understand how implicit
animations are implemented in the first place.
The animations that
CALayer
automatically applies when properties are changed are
called
actions.
When a property of a
CALayer
is modified, it calls its
-actionForKey:
method, passing the name of the property in question. What happens next is quite nicely
documented in the header file for
CALayer
, but it essentially boils down to this:
1.
The layer first checks whether it has a delegate and if the delegate implements the
-actionForLayer:forKey
method specified in the
CALayerDelegate
protocol. If it does, it will call it and return the result.
2.
If there is no delegate, or the delegate does not implement
-actionForLayer:forKey
, the layer checks in its
actions
dictionary,
which contains a mapping of property names to actions.
3.
If the
actions
dictionary does not contain an entry for the property in question,
the layer searches inside its
style
dictionary hierarchy for any actions that match
the property name.
4.
Finally, if it fails to find a suitable action anywhere in the
style
hierarchy, the
layer will fall back to calling the
-defaultActionForKey:
method, which
defines standard actions for known properties.
The result of this exhaustive search will be that
-actionForKey:
either returns
nil
(in
which case, no animation will take place and the property value will change immediately)
or an object that conforms to the
CAAction
protocol, which
CALayer
will then use to
animate between the previous and current property values.
And that explains how UIKit disables implicit animations: Every
UIView
acts as the
delegate for its backing layer and provides an implementation for the
-actionForLayer:forKey
method. When not inside an animation block,
UIView
returns
nil
for all layer actions, but within the scope of an animation block it returns non-
nil values. We can demonstrate this with a simple experiment (see Listing 7.5).
Listing 7.5
Testing UIView's
actionForLayer:forKey:
Implementation
@interface
ViewController ()