The original link: z251257144. Making. IO/ios/UI/UIVi…

Uiviews are very similar in concept to CALayer, which are also rectangular blocks that are managed by hierarchical trees, and can also contain content that manages the position of sublayers. The difference is that UIView can handle touch events; CALayer does not handle user interactions and does not participate in response event passing.

Each UIView has a layer property of a CALayer instance, which we can also access through the Layer property of UIView. The view’s responsibility is to create and manage this layer to ensure that when subviews are added or removed from the hierarchy, their associated layers also perform the same actions in the hierarchy tree.

For UIView, what’s really responsible for displaying content is its internal CALayer, and UIView just gives its presentation to its internal CALayer, and it’s also responsible for some other tasks, like user interaction, Provides some high-level interfaces to the underlying methods of Core Animation.

Consider: why do we provide parallel hierarchies based on UIView and CALayer? A: The reason is to separate responsibilities and avoid duplicate code. Events and user interaction are different in many ways on iOS and Mac OS, and a multi-touch based user interface is fundamentally different from a mouse-and-keyboard based interface. In iOS system, WE use UIKit and UIView, while in MacOS system, we use AppKit and NSView. Therefore, in this case, separating the display part from CALayer will bring convenience to Apple’s multi-platform system development.

define

UIView definition

@interface UIView : UIResponder <NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem, UITraitEnvironment, UICoordinateSpace, UIFocusItem, UIFocusItemContainer, CALayerDelegate>

@property(class.nonatomic.readonly) Class layerClass; // default is [CALayer class]. Used when creating the underlying layer for the view.
@property(nonatomic,readonly,strong) CALayer  *layer; // returns view's layer. Will always return a non-nil value. view is layer's delegate

@end
Copy the code

CALayer definition

@interface CALayer : NSObject <NSSecureCoding, CAMediaTiming>
Copy the code

UIResponder definition

@interface UIResponder : NSObject <UIResponderStandardEditActions>
Copy the code

As you can see from the class definition, CALayer inherits from NSObject; UIView inherits from UIResponder, UIResponder inherits from NSObject. The structure is as follows:

Each UIView has a non-empty layer, which is CALayer by default; The View is the Layer delegate, the delegate protocol is CALayerDelegate, UIView implements the CALayerDelegate method inside.

CALayerDelegate definition

@protocol CALayerDelegate <NSObject>
@optional

/* If defined, called by the default implementation of the -display
 * method, in which case it should implement the entire display
 * process (typically by setting the `contents' property). */

- (void)displayLayer:(CALayer *)layer;

/* If defined, called by the default implementation of -drawInContext: */

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;

/* If defined, called by the default implementation of the -display method.
 * Allows the delegate to configure any layer state affecting contents prior
 * to -drawLayer:InContext: such as `contentsFormat' and `opaque'. It will not
 * be called if the delegate implements -displayLayer. */

- (void)layerWillDraw:(CALayer *)layer
  API_AVAILABLE(macos(10.12), ios(10.0), watchos(3.0), tvos(10.0));

/* Called by the default -layoutSublayers implementation before the layout
 * manager is checked. Note that if the delegate method is invoked, the
 * layout manager will be ignored. */

- (void)layoutSublayersOfLayer:(CALayer *)layer;

/* If defined, called by the default implementation of the
 * -actionForKey: method. Should return an object implementing 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

Layout relationship

The layout of a CALayer is determined by its anchorPoint, position, bounds, and transform, while a UIView frame simply returns the frame of its layer, UIView’s center and bounds also return properties of their Layer.

CALayer has two types of coordinate systems: “point-based coordinate systems” and “unit-based coordinate systems.”

1. Point-based coordinates: Use point-based coordinates when specifying values that map directly to screen coordinates or must be specified relative to another layer, such as the layer’s Position property. Point-based coordinate system related properties: Bounds, Position, frame.

Unit-based coordinates: Use unit coordinates when values should not be associated with screen coordinates because they are associated with some other value. For example, the anchorPoint property of a layer specifies a point relative to the boundary of the layer itself that can be changed.

Frame: The current layer corresponds to the superLayer coordinate system, frame. Origin is the position relative to the upper left corner of the superLayer, and frame. Size is the current layer size. This is similar to UIView frame.

Bounds: The current layer’s frame relative to itself, bounds. Size and frame.size are the same. Bounds. Origin is the upper-left position relative to itself,bounds. Origin = (0,0).

Position: is a point on the current layer relative to the upper left corner of the superLayer.

AnchorPoint: the value is proportional to bounds.size and the default value is (0.5,0.5). For example, (0,0) and (1,1) represent the upper left corner and lower right corner respectively.

The relationship between the four:

The relationship between frame and bounds is simple; frame.origin = CGMakePoint(0,0) is bounds.

The bounds and position in the CALayer determine the Layer size and position in the superLayer. Although Layer has a frame property, it is actually derived from values in the bounds and position properties and is used less frequently.

The relative relationship between anchorPoint, position, and frame.

ⅰ. When determining the anchor point and changing the frame, the value of position is:

Position. x= frame.origin.x+ anchorpoint. x* bounds.size.width; Position. Y = frame.origin. Y + anchorpoint. y* bound.size. Height;

When the anchor point does not change, the frame changes and the position changes with it.

ⅱ. When the anchor point is determined and position is changed, the value of frame is:

X = position. x-anchorpoint. x* bounds.size.width; Y = position. y-anchorpoint. y* bounds.size.height;

When the anchor point remains unchanged, the position changes and the frame changes with it.

Iii. Change the anchorPoint and the value of frame is as follows:

Frame.origin. x= -anchorpoint. x* bounds.size.width+ position.x; Y = -anchorpoint. y* bounds.size.height+ position.y;

Anchor point changes, position does not affect the frame changes.

Why does the anchor point in the third relationship change, frame instead of position?

Because position is really the position relative to superLayer. The frame. Origin is only passively pushed out by position+anchorPoint * bound.size. Height. Changing the value of anchorPoint actually changes the origin of the frame. It can be seen that **position is the control point of the actual position **. When the anchor point changes, the value of position is fixed and unchanged. What changes dynamically is the origin of the frame.

Attribute conversion formula

UIView中frame = CALayer中frame = CALayer中origin, bounds.size

CALayer中origin = position-(anchorPoint*bounds.size)/2

Bounds in UIView = bounds in CALayer

UIView中center = CALayer中position+bounds.size * anchorPoint

An implicit animation

Each view has a layer, but there are also layers that exist independently of the view, such as CAShapelayer. They don’t need to be attached to a view to display content on the screen.

Basically, when you change any property of a single layer, you trigger a simple animation that transitions from the old value to the new value (this is called implicit animation). However, if you change the same property of layer in view, it will just jump from one frame to the next. Although there is a layer in both cases, when a layer is attached to a view, its default implicitly animated layer behavior does not work.

In the “How to Animate Layer-Backed Views” section of the Core Animation programming guide, there is an explanation of why this is the case:

UIView disables layer animations by default, but re-enables them in the Animation block.

This is because when any animatable layer property changes, Layer looks for and runs the appropriate action to implement the change. Such animations are collectively referred to as actions (or caactions) in Core Animation terminology.

Layer asks for an action to provide for a property change by sending actionForLayer:forKey: message to its delegate. The delegate can respond by returning one of three things:

1. It can return an action object, in which case Layer uses the action.

2. It can return nil, so layer will look elsewhere.

3. It can return an NSNull object that tells Layer that no action needs to be performed and the search will stop.

When layer supports a view behind it, the view is its delegate.

conclusion

UIView: Belongs to the UIKit.framework framework. It is responsible for rendering the content of a rectangular region, animating the rectangular region, responding to the region’s touch events, laying out, and managing one or more subviews

CALAyer: belongs to QuartzCore.framework. It is used to draw content, animate content, and cannot handle user events.

Each UIView has an internal CALayer behind it to draw and display the content, and the size styles of UIView are provided by the internal Layer, which has an additional AnchorPoint than the View. Both are tree hierarchies, with SubLayers inside the layer and SubViews inside the View.

UIView acts as a Layer’s CALayerDelegate when a View is displayed, and the display content of the View depends on the internal CALayer’s display.

The CALayer property is modified to support implicit animation by default. When animating UIView’s Layer, the View acts as a proxy for the Layer, and the Layer requests the corresponding action from the View via actionForLayer:forKey:.

Layer internal maintenance of three layer tree, respectively presentLayer Tree(animation tree), modeLayer Tree(model tree), Render Tree(Render tree), when doing iOS animation, we modify the properties of animation, In the animation is actually the presentLayer property value of the Layer, and the final display on the interface is actually the modelLayer that provides the View.

Reference Documents:

www.jianshu.com/p/ed40da930…

www.jianshu.com/p/c6924e2ab…