👨 🏻 💻 making Demo
Easy to remember:
- Essence: CoreAnimation (CA) is an animation API encapsulated on OpenGL and CoreGraphics for calling gpus
- Relationship: UIView holds a CALayer for drawRect presentation, view is the delegate of this layer, UIView can respond to events
- Animation: the CALayer layer class is the foundation of CoreAnimation and is the parent of all CoreAnimation layers
- CABasicAnimation: Animation with start and stop states
- CAKeyframeAnimation: Additionally specifies the time function between keyframes to implement the animation
- UIView animation principle: animation is realized by calling the actionForLayer:forKey of the layer
- UIView animation overlay method: Change the View property when doing animation, the property value will change immediately, after animation to show the effect. At the end of the animation, another animation will be added, which will overlay, and finally stop at the real position of the view.
- PresentationLayer: the presentationLayer is the presentation state
- ModelLayer: modelLayer is a true state that takes effect immediately
- Example 1: Waterflood animation effect (Mask green permeability)
- Fill the greenHead with content from both directions through the mask
- Example 2: Performance optimization for a large number of rounded corners
- Instead of changing the cornerRadius method, change the mask of the layer directly
- CALayer’s design principles:
- Mechanism and policy separation: The mechanism is stable and the policy is frequently modified
- Overall stability: low bug rate is guaranteed
- Each doing its job: spreading risk
- Reduced exposure: Shaded part of the CALayer interface, easy to use
CoreAnimation
What is CoreAnimation?
CoreAnimation(CA) is a graph-based animation framework provided by Apple.
In Apple’s graphics architecture, CoreAnimation is a set of animation apis encapsulated on top of OpenGL and CoreGraphics, which provide interfaces to access graphics hardware (gpus).
CoreGraphics (CG) is a C language library, which is the basis for the system to draw interfaces, text, images and other UI.
So the position relationship of CoreAnimation should look like this:
GPU — > OpenGL & CoreGraphics — > CoreAnimation
CoreAnimation and QuartzCore?
Main structure of QuartzCore:
- CoreAnimation
- CADisplayLink timer
- CALayer and its subclasses (see link above)
- CAMediaTiming Protocol is related
- CATransaction things
- CATransform3D
QuartzCore references the CoreAnimation header file, similar to wrapping CoreAnimation.
CALayer
In iOS, the UIView we see is displayed through the CALayer in QuartzCore, and the animation effects we’re talking about are added to that CALayer.
The CALayer layer class is the foundation of CoreAnimation and provides a set of abstractions. CALayer is the base of the entire layer class, which is the parent of all the core animation layers
Why does UIView have a Layer to display it?
As we know, QuartzCore is cross-ios and macOS platform, and UIView belongs to UIKit, which is used by iOS development, and corresponds to NSView in AppKit in macOS.
IOS -- > UIKit \ QuartzCore macOS -- > NSView /Copy the code
That’s because macOS is a mouse-pointer based system, which is fundamentally different from iOS’s multi-touch. While iOS is different from macOS in terms of interaction, you can use the same set of technologies at the display level.
Each UIView has a layer property, which is of type CALayer by default. You can also use custom layers
/* View leyer, view is layer proxy */
@property(nonatomic.readonly.strong) CALayer *layer;
Copy the code
The View we see is actually its layer, and we can recognize it through the collection properties in CALayer:
- Bounds: The layer’s bounds is a CGRect value that specifies the layer’s size and bound.origin.
- Position: Specifies the position of the layer (relative to the parent layer)
- AnchorPoint: Specifies the position of position on the current layer, in the range 0 to 1
- Transform: Specifies the geometry transformation of this layer. The type is CATransform3D
For each of these attributes, the comment has an Animatable at the end, which means we can animate by changing these attributes.
By default, we change these properties to cause the layer to animate from the old value to the new value, called implicit animation.
Notice that there is no Animatable in the frame comment. In fact, we can understand that the layer’s frame is not a real property: when we read a frame, we calculate its frame from the layer’s position, bounds, anchorPoint, and Transform values; When we set the frame, the layer changes position and bounds depending on the anchorPoint. That is, the frame itself is not saved.
CALayer also has a uiView-like hierarchy. A view instance has a superView and subView. A layer also has a superLayer and a subLayer. We can add sub-layers directly to the layer of the view to achieve some display effect, but these individual layers cannot interact like UIView.
CAAnimation
CALayer provides the following methods to manage animations:
- (void)addAnimation:(CAAnimation*)anim forKey:(nullable NSString*)key;
- (void)removeAllAnimations;
- (void)removeAnimationForKey:(NSString*)key;
- (nullable NSArray<NSString*>*)animationKeys;
- (nullable CAAnimation*)animationForKey:(NSString*)key;
Copy the code
CAAnimation is the base class of animation. Both CABasicAnimation and CAKeyframeAnimation are inherited from CAPropertyAnimation, that is, property animation.
/** Subclass for property-based animations. **/
CA_CLASS_AVAILABLE (10.5.2.0.9.0.2.0)
@interface CAPropertyAnimation : CAAnimation
/* Creates a new animation object with its `keyPath' property set to * 'path'. */
+ (instancetype)animationWithKeyPath:(nullable NSString *)path;
/* The key-path describing the property to be animated. */
@property(nullable.copy) NSString *keyPath;
/* When true the value specified by the animation will be "added" to * the current presentation value of the property to produce the new * presentation value. The addition function is type-dependent, e.g. * for affine transforms the two matrices are concatenated. Defaults to * NO. */
@property(getter=isAdditive) BOOL additive;
/* The `cumulative' property affects how repeating animations produce * their result. If true then the current value of the animation is the * value at the end of the previous repeat cycle, plus the value of the * current repeat cycle. If false, the value is simply the value * calculated for the current repeat cycle. Defaults to NO. */
@property(getter=isCumulative) BOOL cumulative;
/* If non-nil a function that is applied to interpolated values * before they are set as the new presentation value of the animation's * target property. Defaults to nil. */
@property(nullable.strong) CAValueFunction *valueFunction;
@end
Copy the code
CAPropertyAnimation animates the layer by changing its animatable properties (position, size, etc.).
CABasicAnimation
CABasicAnimation can be regarded as a CAKeyframeAnimation with two keyframes, which form an animation path through each keyframe through interpolation. But CABasicAnimation is a little more flexible:
@interface CABasicAnimation : CAPropertyAnimation
@property(nullable.strong) id fromValue;
@property(nullable.strong) id toValue;
@property(nullable.strong) id byValue;
@end
Copy the code
We can specify the start and stop states of CABasicAnimation by using the above three values:
- All three attributes are optional, and given one or both, the following is the official recommended usage
- Given fromValue and toValue, interpolate between them *
- Given fromValue and byValue, interpolate * between fromValue and fromValue+byValue
- Given byValue and toValue, interpolate * between toValue-byValue and toValue
- Given only fromValue, interpolate * between the fromValue and the current value
- Given only toValue, interpolate * between the current value and toValue
- Given only byValue, interpolate * between the current value and the current value +byValue
CAKeyframeAnimation
In CAKeyframeAnimation, you can specify the time between key frames and the time function:
@interface CAKeyframeAnimation : CAPropertyAnimation
@property(nullable.copy) NSArray *values;
@property(nullable.copy) NSArray<NSNumber *> *keyTimes;
/* Time functions have simple effects such as linear, fade in, fade out, etc. You can also specify a cubic Bezier curve */
@property(nullable.copy) NSArray<CAMediaTimingFunction *> *timingFunctions;
@end
Copy the code
We can already feel that the so-called animation is actually different pictures at different times, and time is moving and forming a continuous change effect. So, the key to animation is time control.
CAMediaTiming
CAMediaTiming is a very important protocol in CoreAnimation. Both CALayer and CAAnimation implement it to manage time.
The protocol defines eight attributes that control time, most of which are known by name:
@protocol CAMediaTiming
@property CFTimeInterval beginTime;
@property CFTimeInterval duration;
@proterty float speed;
/* timeOffset specifies the timeOffset used to pause, continue, etc. */
@proterty CFTimeInterval timeOffset;
@property float repeatCount;
@property CFTimeInterval repeatDuration;
/* Autoreverses will be returned after time ends (default: false */)
@property BOOL autoreverses;
/* fillMode Four filling modes are available, as shown in */
@property(copy) NSString *fillMode;
@end
Copy the code
The following diagram illustrates how flexible these properties are for animation time control:
Note that CALayer also implements the CAMediaTiming protocol, which means that if we set layer speed to 2, animations added to this layer will be executed at twice the speed.
Above, we have a brief understanding of CALayer, attribute animation and animation time control from the relationship between layer, animation and time control. We know that attribute animation is realized by interpolating between key frames according to time and continuously changing an animation attribute of layer over time.
UIView and CALayer animation principles
The following two points are combined with specific codes to explore some principles of CoreAnimation
- 1. Implementation principle of UIView animation
- 2. PresentationLayer and modelLayer
UIView animation implementation principle
UIView provides a series of UIViewAnimationWithBlocks, we only need to add the code that changes can be animated properties on the block animations can be realized in the animation effects, such as:
[UIView animateWithDuration:1 animations:^(void) {if (_testView.bounds.size.width > 150) {
_testView.bounds = CGRectMake(0.0.100.100);
} else {
_testView.bounds = CGRectMake(0.0.200.200);
}
} completion:^(BOOL finished){
NSLog(@"%d",finished);
}];
Copy the code
The effect is as follows:
As mentioned earlier, UIView objects hold a CALayer, and it’s this layer that really animates. UIView just encapsulates it. We can verify this with a simple experiment: Let’s write a MyTestLayer class that inherits CALayer and rewrite its set method. Write a MyTestView class that inherits UIView and override its layerClass method to specify the layerClass as MyTestLayer:
MyTestLayer implementation:
@interface MyTestLayer : CALayer
@end
@implementation MyTestLayer
- (void)setBounds:(CGRect)bounds {
NSLog(@"----layer setBounds");
[super setBounds:bounds];
NSLog(@"----layer setBounds end"); }...@end
Copy the code
MyTestView implementation:
@interface MyTestView : UIView
- (void)setBounds:(CGRect)bounds {
NSLog(@"----view setBounds");
[super setBounds:bounds];
NSLog(@"----view setBounds end"); }... + (Class)layerClass {return [MyTestLayer class];
}
@end
Copy the code
When we set bounds to the view, the getter and setter are called in this order:
That is, in the View’s setBounds method, the layer’s setBounds are called; Similarly, the View’s getBounds call the Layer’s getBounds. The same is true for other attributes. So how does animation come about? When the properties of our layer change, we will call the proxy method actionForLayer: forKey: to get the animation scheme of the property change, and view is the proxy of the layer it holds:
@interface CALayer : NSObject <NSCoding.CAMediaTiming>.@property(nullable.weak) id <CALayerDelegate> delegate; .@end
@protocol CALayerDelegate <NSObject>
@optional./* If defined, called by the default implementation of the * -actionForKey: method. Should return an object implementating the * CAAction protocol. May return 'nil' if the delegate doesn't specify * a behavior for the current event. Returning the null object (i.e. * '[NSNull null]') explicitly forces no further search. (I.e. the * +defaultActionForKey: method will not be called.) */
- (nullable id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString*)event; .@end
Copy the code
As noted in the comment, this method returns an object that implements CAAction, usually an animation object; The default implicit animation is performed when nil is returned, and no animation is performed when null is returned. In the same animation that changed bounds above, we override the actionForLayer: method in MyTestView
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
id<CAAction> action = [super actionForLayer:layer forKey:event];
return action;
}
Copy the code
Observe its return value:
Is an internal use _UIViewAddtiveAnimationAction object, which contains a CABassicAnimation, default fillMode for both, the default time function for fades, contains only fromValue (namely the value of the animation before, Animates between this value and the current value (the modified value in the block). We could try to force a nil return in our overridden method and see that changing the property without writing any animation code would also result in an implicit animation of 0.25s by default, as described in the comment above.
Explicit and implicit animation
Explicit animations are animations created by the user themselves with beginAnimations: Context: and commitAnimations.
Implicit animation (iOS 4.0) is to point to by UIView animateWithDuration: animations: method to create the animation.
What would happen if two animations were superimposed?
Again from the original example, we add two identical UIView animations, one for 3s and one for 1s, and print the finished value and the duration of the two animations. Execute the 3s animation first, and add a 1s animation when it is not finished, you can see the actual effect first:
The log print
Obviously, the finished for both animations is true and the time we set is 3s and 1s. This means that the second animation does not interrupt the execution of the first animation, but instead overlays the animation.
Animation’s sad journey:
- The block starts out with the bounds of (100,100), clicks to animate the 3s, changes the bounds to (200,200), and displays a larger animation;
- During the animation (suppose at (120,120)), click on the animation for 1s. Since the real bounds are already at (200,200), the bounds will change back to 100 and generate an animation with fromValue of (200,200).
But instead of starting at 200, the square immediately starts to get smaller and becomes significantly smaller than 100.
- The finished animation takes 1s. The finished animation takes 1 seconds. At this point, the block on the screen is smaller than 100, then slowly returns to the 100-3s animation, finished is 1, and the block ends at (100,100).
From this we can guess how UIView animation is superimposed: when we animate by changing the View property, the value of the property is immediately changed, and the animation is just the displayed effect. If you add another animation to the same property while the animation is still running, the two animations will start superimposing from the current state and end up in the real position of the view.
Take a popular example, we start from home at 8 o ‘clock and arrive at school at 9 o ‘clock. We walk at a normal pace, which can be understood as an animation. If we forgot to take our bag halfway suddenly thought of, need to go home to take bag (equivalent to add a animation), then we certainly need to speed up the pace, when we get a bag is equivalent to a second end of the animation, but we will continue to perform the animation school, we will continue to drive to school, at the rate of right guarantee at nine o ‘clock to the finish – school on time.
So just why that square has a smaller than 100 process is easy to understand: when added the second animation, because it is a 1 s from 200 to 100 of the animation, certainly faster than 3 s animation execution, and begins with the location of the 120 executive, so will be in the opposite direction to the smaller than 100; After the 1s animation, it will return to the final position (100,100) at the appropriate speed at 3s time point. Of course, the entire process after superposition may be calculated in internal implementation according to the time function.
This may be done to make the animation smoother, but since we set the property value immediately and the animation is just what it looks like, what is the position of the screen display at the moment of overlay (120,120)? That’s the next topic in this article.
PresentationLayer and modelLayer
We know that UIView animation is actually done at the layer, and the view encapsulates the layer, and what we’re doing to properties like the View bounds and things like that are actually doing to the layer that it’s holding, Let’s do a simple experiment — after changing the bounds of a UIView animation block, check the actual values of the bounds of both view and layer:
_testView.bounds = CGRectMake(0.0.100.100);
[UIView animateWithDuration:1 animations:^(void){
_testView.bounds = CGRectMake(0.0.200.200);
} completion:nil];
Copy the code
Once the assignment is complete, we print the View and layer bounds separately:
The bounds of the set view are actually set to the bounds of its layer. But isn’t animation implemented by Layer? Now that Layer has reached its destination, how does it animate it?
Here are two instances of CALayer methods presentationLayer and modelLayer:
@interface CALayer : NSObject <NSCoding.CAMediaTiming>./* See the official API notes */
/* presentationLayer * returns a copy of the layer, if any animation is active, containing all layer properties * that are actually approximations to the current state. * Attempts to modify the result returned in any way are undefined. Sublayers, mask, and superLayer return values that are presentationLayer */ for these properties of the current layer
- (nullable instancetype)presentationLayer;
/* modelLayer * calls presentationLayer to return the current model value. * On a non-PresentationLayer call, returns itself. * The result of calling this method after the transaction that generated the presentation layer is undefined. * /
- (instancetype)modelLayer; .Copy the code
From the comments, it is not difficult to see that the presentationLayer is the state we see displayed on the screen, and modelLayer is the real state that takes effect immediately after we set it. After the animation starts, we delay printing layer, layer.presentationLayer, respectively. Layer. ModelLayer and layer. PresentationLayer. ModelLayer:
Obviously, layer presentationLayer is the value of the current state of the animation, and layer. ModelLayer and layer presentationLayer. ModelLayer layer itself.
By now, the principle of CALayer animation is basically clear. When an animation is added, the presentationLayer will constantly value (from the animation path obtained by some interpolation or approximation) to display, and when the animation is removed, the state of modelLayer will be displayed. This is why when we use CABasicAnimation, we set the current value to fromValue and the animation ends up going back to the beginning. In fact, the animation ends up not going back to the beginning but to the modelLayer.
Although we can use the fillMode control it at the end of the stay, but this method after the execution of the animation is not removed the animation from the tree (because we need to set up animation. RemovedOnCompletion = NO effect to make fillMode). If we want the animation to stop at the end, it makes more sense to set the layer to the end state at the beginning, which is exactly what the UIView block animation does.
If we set the layer to the end state at the beginning and add the animation, will the animation flash at the end position? No, because what we’re actually seeing is the presentationLayer, and if we change the properties of the layer, the presentationLayer doesn’t change immediately:
MyTestView *view = [[MyTestView alloc]initWithFrame:CGRectMake(200.200.100.100)];
[self.view addSubview:view];
view.center = CGPointMake(1000.1000);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((1/60) * NSEC_PER_SEC)), dispatchQueue, ^{
NSLog(@"presentationLayer %@ y %f",view.layer.presentationLayer, view.layer.presentationLayer.position.y);
NSLog(@"layer.modelLayer %@ y %f",view.layer.modelLayer,view.layer.modelLayer.position.y);
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((1/20) * NSEC_PER_SEC)), dispatchQueue, ^{
NSLog(@"presentationLayer %@ y %f",view.layer.presentationLayer, view.layer.presentationLayer.position.y);
NSLog(@"layer.modelLayer %@ y %f",view.layer.modelLayer,view.layer.modelLayer.position.y);
});
Copy the code
In the code above we change the center of the view, the modelLayer changes immediately because it is the Layer itself. However, the presentationLayer does not change. We try to delay retrieving the presentationLayer for a certain amount of time and find that it changes after a very short time, which is related to the screen refresh rate of the specific device.
That is, after we set the layer properties, the presentationLayer won’t get the new value until the next screen refresh. Because it is impossible to draw every property change, we save these changes in the Model layer and redraw them at the next screen refresh.
If we add an animation and set the modelLayer to the endpoint, the presentationLayer will preferentially draw from the animation on the next screen refresh, so there will be no flash at the endpoint.
The subtotal
- UIView holds a CALayer for presentation, and the view is the delegate of this layer. Changing the properties of a view actually changes the properties of the layer it holds. When the properties of the layer change, the proxy method actionForLayer: forKey: is called to determine whether the change requires animation. The overlay animation of the same property starts from the current display state and ends at the real location of the modelLayer.
- CALayer internally controls two properties, presentationLayer and modelLayer. ModelLayer is the real state of the current layer, and presentationLayer is the on-screen state of the current layer. The presentationLayer updates the state each time the screen is refreshed, draws based on the current state of the animation if there is one, and takes the state of the modelLayer when the animation is removed.
A preliminary study on CALayer attributes
The difference between CALayer and UIView
- 1.UIView is UIKit (iOS only), CALayer is QuartzCore (iOS and MAC OS)
- UIView inherits UIResponder, and CALayer inherits NSObject.UIView has one more event handling function than CALayer. That is,CALayer can’t handle user touch events, whereas UIView can
- 3.UIView comes from CALayer, which is the high-level implementation and encapsulation of CALayer. All features of UIView come from CALayer support
- 4.CABasicAnimation, CAAnimation, CAKeyframeAnimation and other animation classes need to be added to CALayer
In fact, UIView only shows up on the screen because of a layer inside it. When UIView object is created, a layer (CALayer object) is automatically created inside UIView, and this layer is accessible through UIView’s Layer property.
@property(nonatomic.readonly.retain) CALayer *layer;
Copy the code
When the UIView needs to be displayed on the screen, it calls the drawRect: method and draws everything on its own layer. When the drawing is done, the system copies the layers onto the screen and the UIView is displayed.
In other words, UIView doesn’t display itself, it’s the layers inside it that do
CALayer property sheet
Use CALayer’s Mask for waterflood animation
Core Animation has always been an interesting topic in iOS. It can achieve very smooth and cool Animation by using Core Animation. Core Animtion API is a higher level of encapsulation, easy to use, so we do not have to use OpenGL animation implementation.
How to use CALayer’s mask to create a bidirectional waterflood animation
Learn about CALayer’s mask
@property(strong) CALayer *mask;
Copy the code
Mask is actually a mask for the contents of the layer.
If the mask is set to transparent, the actual layer is completely transparent, that is, only the opaque part of the mask content is superimposed on the layer.
Implementation idea: The design idea refers to the smooth realization of KTV lyrics view based on Core Animation (http://www.iwangke.me/2014/10/06/how-to-implement-a-core-animation-based-60-fps-ktv-lyrics-view/)
Flow puts two UIImageViews on top of each other: grayHead and greenHead. By default, the greenHead hides the grayHead.
Set a mask for greenHead. This mask is not a normal mask. It consists of two subLayer:maskLayerUp maskLayerDown.
By default, sublayers are displayed outside of the mask content, so the mask is actually transparent and so is the greenHead.
Now that we want greenHead to slowly display content from the top left and bottom right, we just need to populate greenHead from both directions.
Create a Mask mask
- (CALayer *)greenHeadMaskLayer {
CALayer *mask = [CALayer layer];
mask.frame = self.greenHead.bounds;
self.maskLayerUp = [CAShapeLayer layer];
self.maskLayerUp.bounds = CGRectMake(0.0.30.0f, 30.0f);
self.maskLayerUp.fillColor = [UIColor greenColor].CGColor; // Any color but clear will be OK
self.maskLayerUp.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(15.0f, 15.0f)
radius:15.0f
startAngle:0
endAngle:2*M_PI
clockwise:YES].CGPath;
self.maskLayerUp.opacity = 0.8f;
self.maskLayerUp.position = CGPointMake(5.0f, 5.0f);
[mask addSublayer:self.maskLayerUp];
self.maskLayerDown = [CAShapeLayer layer];
self.maskLayerDown.bounds = CGRectMake(0.0.30.0f, 30.0f);
self.maskLayerDown.fillColor = [UIColor greenColor].CGColor; // Any color but clear will be OK
self.maskLayerDown.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(15.0f, 15.0f)
radius:15.0f
startAngle:0
endAngle:2*M_PI
clockwise:YES].CGPath;
self.maskLayerDown.position = CGPointMake(35.0f, 35.0f);
[mask addSublayer:self.maskLayerDown];
return mask;
}
Copy the code
Do Angle animation
- (void)startGreenHeadAnimation {
CABasicAnimation *downAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
downAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(5.0f, 5.0f)];
downAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(10.0f, 10.0f)];
downAnimation.duration = duration;
[self.maskLayerUp addAnimation:downAnimation forKey:@"downAnimation"];
CABasicAnimation *upAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
upAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(35.0f, 35.0f)];
upAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(20.0f, 20.0f)];
upAnimation.duration = duration;
[self.maskLayerDown addAnimation:upAnimation forKey:@"upAnimation"];
}
Copy the code
To summarize:
- CALayer provides another way to manipulate the UI, and while it provides a lower-level API than UIView, it offers richer functionality and higher performance (CALayer animations are rendered on dedicated threads). CALayer is especially useful when it comes to complex and high-performance UI interfaces, such as AsyncDisplayKit.
- Usually, when dealing with rounded corners, we will directly change the cornerRadius of CALayer. But this approach has poor performance, especially when placing it in a list. Now that we have mask, we can directly change the mask of the layer. Without affecting the performance of graphics rendering.
Say a little more
Why UIView when you have a CALayer
UIView inherits from UIResponder, and its main feature is that it can respond to touch events. CALayer does the actual layer content management. We do different things, are two things, we do not affect each other, of course.
UILayer
So let’s say I have a UIView and a CALayer, UILayer and that UILayer is an all-in-one Layer that manages the display, but also handles touch events.
But due to the update of iOS system, so you have to constantly modify the maintenance of UILayer, such as iOS3.2 version increased gesture recognition, iOS4 introduced Block syntax, iOS6 increased AutoLayout feature, iOS7 UI had to be reinvented, each time to open a huge length of UILayer changed from the beginning to the foot. The maintenance costs are too high.
Therefore, behind this natural SDK, there are daniumen decades of design wisdom. You should be able to see a lot of doors. This time, if we do UIView and CALayer, we’ll get something.
Design principles in this regard:
- Mechanism and policy are separated
- The overall stability
- Do their job
- Reduce exposure
Mechanism and policy are separated
One of the main ideas of the Unix kernel design is to provide a Mechanism rather than a Policy. Programming problems can be isolated from mechanics and strategy. Once implemented, mechanisms rarely change, but policies are often optimized. Atoms, for example, can be seen as mechanisms, and the composition of atoms as a strategy.
CALayer can also be viewed as a mechanism that provides layer drawing, and if you look at CALayer’s header file, it’s basically unchanged, and UIView can be viewed as a strategy, it’s changed a lot. The lower you go, the more mechanism you have, the more stable the mechanism is. The separation of mechanism and policy results in less code that needs to be modified, especially the underlying code, which improves system stability.
The overall stability
How does stability make you feel? Strong? Non-deformable? Stability is immutable. The more immutable things a system is, the more stable it is. So the mechanism satisfies this immutable factor. One of the guiding ideas in building a system is to try to extract immutable things and separate mutable things. Water doesn’t make tall buildings, solid concrete does. Less modification means less chance of bugs.
Do their job
Even if ability again big also can’t say to have the matter all stem, in case which day can’t line up, that is suddenly what all can’t stem. Therefore, there should not be omnipotent classes just based on the principle of risk diversification. Working with each other to minimize controllable granularity can also make the system more stable and modifiable.
Reduce exposure
Interfaces should be open to the public, according to the 82 principle, in fact, 20% of the interface can meet 80% of the needs, the remaining 80% should be hidden behind. Because it’s always safe to leak less, right? The remaining 80% of expert interfaces can be hidden and deep. UIView, for example, overshadowing most of the CALayer interface, abstracts and constructs more usable frame and animation implementations that make it easier to get started.
Above post since: https://blog.csdn.net/zmmzxxx/article/details/74276077# a calayer profile