Layer behavior (implicit animation), layer behavior
Layer behavior
Now let's make an experiment and try to directly animation the layers associated with UIView instead of a separate layer. Listing 7.4 is a slight modification to listing 7.2 code, removedcolorLayer
And directly setlayerView
The background color of the associated layer.
Listing 7.4 directly sets the properties of a Layer
1 @interface ViewController () 2 3 @property (nonatomic, weak) IBOutlet UIView *layerView; 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad10 {11 [super viewDidLoad];12 //set the color of our layerView backing layer directly13 self.layerView.layer.backgroundColor = [UIColor blueColor].CGColor;14 }15 16 - (IBAction)changeColor17 {18 //begin a new transaction19 [CATransaction begin];20 //set the animation duration to 1 second21 [CATransaction setAnimationDuration:1.0];22 //randomize the layer background color23 CGFloat red = arc4random() / (CGFloat)INT_MAX;24 CGFloat green = arc4random() / (CGFloat)INT_MAX;25 CGFloat blue = arc4random() / (CGFloat)INT_MAX;26 self.layerView.layer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;27 //commit the transaction28 [CATransaction commit];29 }
View Code
Run the program and you will find that when you press the button, the layer color instantly switches to the new value, instead of the previous smooth transition animation. What happened? Implicit animation seems to beUIView
The associated layer is disabled.
Imagine ifUIView
If all attributes have animation properties, we should be able to notice when we modify them. Therefore, if UIKit is built on Core Animation (Animation for everything by default), how can implicit Animation be disabled by UIKit?
We know that Core Animation usually correspondsCALayer
All attributes (animation attributes)UIView
Disable the feature of the layer associated with it. To better illustrate this, we need to know how implicit animation is implemented.
When we change the attributeCALayer
The animation automatically applied is calledAction, WhenCALayer
When the attribute of is modified, it will call-actionForKey:
Method to pass the attribute name. The remaining operations areCALayer
The header file is described in detail as follows:
- The layer first checks whether it has delegation and whether it is implemented.
CALayerDelegate
Protocol-specified-actionForLayer:forKey
Method. If yes, call and return the result.
- If there is no delegate, or the delegate is not implemented
-actionForLayer:forKey
Method, the layer then checksactions
Dictionary.
- If
Actions dictionary
The layer does not contain the corresponding attributes.style
The dictionary then searches for the attribute name.
- Finally, if
style
The corresponding behavior cannot be found, so the layer will directly call-defaultActionForKey:
Method.
So after a complete search,-actionForKey:
Either return NULL (in this case, no animation will occur) orCAAction
The object corresponding to the Protocol.CALayer
Use this result to animation previous and current values.
This explains how UIKit disables implicit Animation: eachUIView
Each layer associated with it plays a delegate and provides-actionForLayer:forKey
. When not implementing an animation block,UIView
Returns the behavior of all layers.nil
But within the animation block range, it returns a non-null value. We can use a demo to do a simple experiment (listing 7.5)
Listing 7.5actionForLayer:forKey:
Implementation
1 @interface ViewController () 2 3 @property (nonatomic, weak) IBOutlet UIView *layerView; 4 5 @end 6 7 @implementation ViewController 8 9 - (void)viewDidLoad10 {11 [super viewDidLoad];12 //test layer action when outside of animation block13 NSLog(@"Outside: %@", [self.layerView actionForLayer:self.layerView.layer forKey:@"backgroundColor"]);14 //begin animation block15 [UIView beginAnimations:nil context:nil];16 //test layer action when inside of animation block17 NSLog(@"Inside: %@", [self.layerView actionForLayer:self.layerView.layer forKey:@"backgroundColor"]);18 //end animation block19 [UIView commitAnimations];20 }21 22 @end
View Code
Run the program. The console displays the following results:
1 $ LayerTest[21215:c07] Outside: <null>2 $ LayerTest[21215:c07] Inside: <CABasicAnimation: 0x757f090>
View Code
So we can predict that when the attribute changes outside the animation block,UIView
Directly returnnil
To disable implicit animation. However, if the corresponding attributes are returned Based on the animation type within the animation block range, in this exampleCABasicAnimation
(As mentioned in chapter 8 "Explicit Animation ).
Certainly returnnil
It is not the only way to disable implicit animation,CATransacition
There is a method called+setDisableActions:
To enable or disable implicit animation for all attributes. If[CATransaction begin]
Then add the following code to prevent the animation from occurring:
[CATransaction setDisableActions:YES];
To sum up, we know the following points:
UIView
Implicit animation is disabled for the associated layers. The only way to do animation for this layer is to useUIView
Instead of relying onCATransaction
), Or inheritUIView
And Overwrite-actionForLayer:forKey:
Method, or directly create an explicit animation (for details, see Chapter 8 ).
- For an independent layer, we can implement
-actionForLayer:forKey:
Delegate method, or provideactions
Dictionary to control implicit animation.
Let's use a different behavior for the color gradient example.colorLayer
Set a customactions
Dictionary. We can also use Delegation for implementation,actions
Dictionary can write less code. So how can we create a suitable behavior object?
The behavior is usually caused by Core Animation.ImplicitCalledExplicitAnimation object. Here we use an implementationCATransaction
Instance, calledAdvance transition.
The transition will be explained in detail in Chapter 8.CATransition
ResponseCAAction
Protocol, and can be used as a layer action. The results are very good. No matter when the background color is changed, the new color block slides in from the left side, rather than the default gradient effect.
Listing 7.6 custom Behaviors
1 @ interface ViewController () 2 3 @ property (nonatomic, weak) IBOutlet UIView * layerView; 4 @ property (nonatomic, weak) IBOutlet CALayer * colorLayer; /* the enthusiastic person finds that this should be changed to @ property (nonatomic, strong) CALayer * colorLayer; otherwise, the running result is incorrect. 5 */6 7 @ end 8 9 @ implementation ViewController10 11-(void) viewDidLoad12 {13 [super viewDidLoad]; 14 15 // create sublayer16 self. colorLayer = [CALayer layer]; 17 self. colorLayer. frame = CGRectMake (501_f, 501_f, 1001_f, 1001_f); 18 self. colorLayer. backgroundColor = [UIColor blueColor]. CGColor; 19 // add a custom action20 CATransition * transition = [CATransition animation]; 21 transition. type = kCATransitionPush; 22 transition. subtype = kCATransitionFromLeft; 23 self. colorLayer. actions =@{@ "backgroundColor": transition}; 24 // add it to our view25 [self. layerView. layer addSublayer: self. colorLayer]; 26} 27 28-(IBAction) changeColor29 {30 // randomize the layer background color31 CGFloat red = arc4random ()/(CGFloat) INT_MAX; 32 CGFloat green = arc4random () /(CGFloat) INT_MAX; 33 CGFloat blue = arc4random ()/(CGFloat) INT_MAX; 34 self. colorLayer. backgroundColor = [UIColor colorWithRed: red green: green blue: blue alpha: 1.0]. CGColor; 35} 36 37 @ end38
View Code