Layer geometry

In this chapter, we’ll take a look at how the inside of a layer controls its position and size based on its parent and sibling layers. We will also cover how to manage the structure of the layer collection and how it is affected by automatic adjustment and automatic layout.

layout

UIView has three important layout properties: Frame, bounds and Center, and CALayer is called frame, bounds and Position.

Frame represents the outer coordinates of the layer (that is, the space it occupies on the parent layer), bounds is the inner coordinates ({0, 0} is usually the top left corner of the layer), and Center and Position both represent the location of the anchorPoint relative to the parent layer.

Remember that when you transform a layer, such as rotation or scaling, the frame actually represents the rectangular area covering the entire axis alignment of the layer after rotation. This means that the width and height of the frame may no longer match the width and height of the bounds.

The anchor

The center property of the view and the position property of the layer both specify the anchorPoint position relative to the parent layer. The anchorPoint of the layer controls the position of its frame. You can think of the anchorPoint as the handle used to move the layer.

By default, anchorPoint is in the middle of the layer, so the layer will be centered around that point. The anchorPoint property is not exposed by the UIView interface, which is why the view’s position property is called “Center.” However, the anchorPoint of the layer can be moved. For example, you can place it in the top left corner of the layer frame, so the contents of the layer will be moved to position in the bottom right corner, instead of centered.

Similar to the previous contentsRect and contentsCenter properties, anchorPoint is described as a unit coordinate, which is the relative coordinate of the layer. The top left corner of the layer is {0, 0}, and the bottom right corner is {1, 1}, so the default coordinate is {0.5, 0.5}. AnchorPoint can be placed out of layer range by specifying x and y values less than 0 or greater than 1.

The book uses a project that simulates an alarm clock to illustrate when the anchorPoint needs to be changed. The original picture of the clock rotates around the center, which can be achieved by some translation of the achorPoint of each hand to obtain a desired fulcrum.

Coordinate system

Like views, layers are placed hierarchically in the layer tree relative to their parent layer. A layer’s position depends on its parent layer’s bounds. If the parent layer moves, all its child layers move as well.

This makes it easier to place layers because you can move the root layer to move its children as a whole by moving it, but sometimes you need to know the absolute position of a layer, or its position relative to another layer, rather than its current parent.

CALayer provides some utility class methods for converting layers between coordinate systems:

- (CGPoint)convertPoint:(CGPoint)point fromLayer:(CALayer *)layer;
- (CGPoint)convertPoint:(CGPoint)point toLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect fromLayer:(CALayer *)layer;
- (CGRect)convertRect:(CGRect)rect toLayer:(CALayer *)layer;
Copy the code

These methods convert points or rectangles defined in one layer coordinate system to points or rectangles defined in another layer coordinate system.

Flipped geometry

Normally, on iOS, a layer’s position is in the upper-left corner of the parent layer, but on Mac OS, it’s usually in the upper-left corner. Core Animation can accommodate both cases with the geometryFlipped property, which determines whether the coordinates of a layer are flipped vertically relative to the parent layer and are of type BOOL. Setting it to YES on iOS means that its child layers will be flipped vertically, i.e. will be arranged along the bottom instead of the usual top (the same goes for all of its child layers unless you set their geometryFlipped property to YES as well).

The Z axis

Unlike THE strict two-dimensional coordinate system of UIView, a CALayer exists in a three-dimensional space. In addition to the position and anchorPoint properties we’ve already discussed, the CALayer has two other properties, zPosition and anchorPointZ, both of which are floating point types that describe the position of a layer on the Z axis.

Usually, layers are drawn in the order in which the subLayers of their child layers appear. This is called the artist algorithm — think of an artist drawing on a wall — the layer being drawn will hide the previous layer, but by increasing the layer’s zPosition, you can move the layer forward towards the camera. It is then in front of all other layers (or at least in front of layers less than its zPosition).

Hit Testing

The CALayer doesn’t care about any response chain events, so it can’t handle touch events or gestures directly. But it does have a series of methods to handle events for you: containsPoint and hitTest.

ContainsPoint accepts a CGPoint in this layer’s coordinates and returns YES if the point is within the frame of the layer.

The hitTest method also takes a parameter of type CGPoint, not BOOL, and returns either the layer itself, or the leaf node layer containing the coordinate point. This means that you no longer need to manually transform or test the coordinates clicked on each sublayer, as with containsPoint. If this point is outside the scope of the outermost layer, it returns nil.

Note that when calling the hitTest method on a layer, the order of measurement depends strictly on the order of layers within the layer (similar to how UIView handles events). The previously mentioned zPosition property significantly changes the order of the layers on the screen, but it does not change the order in which touch events are processed.

This means that if you change the z-order of the layers, you will notice that the front-most view click event will not be detected because it will be hidden by another layer, which has a smaller zPosition but is in a higher order in the layer tree.

Automatic layout

When using views, you can take full advantage of the UIViewAutoresizingMask and NSLayoutConstraintAPI exposed by the UIView class interface, but if you want to arbitrarily control the layout of the CALayer, you need to do it manually. The easiest way to do this is to use the CALayerDelegate function:

-(void)layoutSublayersOfLayer:(CALayer*)layer;
Copy the code

This function is executed when the layer’s bounds change or the layer’s setNeedsLayout method is called. This allows you to manually rearrange or resize subviews, but not to adapt to screen rotation like the autoresizingMask and constraints properties of UIView.

This is another important reason why it is best to use views instead of separate layers to build applications.

conclusion

This chapter covers the geometry of the CALayer, including its frames, positions, and bounds, introduces the concept of layers within a three-dimensional space, and how to respond to events within separate layers. Finally, it briefly explains the lack of automatic adjustment and layout support in Core Animation on iOS.