Introduction
Understanding how the layout engine works under the hood is crucial. In this article, we will delve into the layout engine to gain a better understanding of its workings.
Table of contents
Open Table of contents
The Layout Pass
When you add, update, and remove constraint the layout doesn’t change immediately. Recalculating and updating the layout for every change would be inefficient. Instead, these changes schedule the layout engine associated with the window to perform a layout pass during the next application run loop.
The layout cycle has the following steps:
- Trigger. All changes that you make to views affect an input of the layout engine. This can include changing or removing constraints, altering the intrinsic content size, and more.
- Update Model. The layout engine has an inner model of the size and position of each element on the screen, as well as the equations that describe the relationships between those views. When you change an input it causes the layout engine to update its internal model and solve equations for new values for the size and position for each view. At this stage, only the inner model has changed. Views that need to be updated call
setNeedsLayout()
on their superview to schedule a deferred layout pass. The layout will be calculated later on the application run loop. - Deferred Layout Pass. The layout pass makes two passes over the view hierarchy. The first pass through the view hierarchy is from bottom-up and gives you the last chance to change the layout. The second pass through the view hierarchy is a top-down, which finally calls
layoutSubviews()
on each view, allowing them to update their sizes and positions based on the inner model.
You can override some method to interact with layout engine during two layout passes:
- When a view updates its constraints the layout engine calls the view controller’s
updateViewConstraints
method for all views with pending updates. - When a view performs a layout pass the layout engine calls the view controller’s
viewWillLayoutSubviews
andviewDidLayoutSubviews
methods and thelayoutSubviews
method of any views pending layout.
Updating Constraints
As mentioned above, the first pass through the view hierarchy is from bottom-up, giving you the last chance to change the layout. The layout engine calls updateConstraintsIfNeeded
on each view to check if it has the latest constraints. If a view is marked as requiring updates to its constraints, the layout engine calls the updateConstraints
method, where you can implement these changes.
Updating Layout
The second pass through the view hierarchy is a top-down pass to reposition the views. This pass only updates the view frames according to their inner model. If a view is pending an update, layoutSubviews
sets the bounds and center of each subview to the new values from the inner model. If you have a custom layout that can’t be implemented using constraints, you can just implement it manually inside layoutSubviews
.
Summary
This article explains how the layout engine in iOS works, including how changes to constraints trigger a deferred layout pass in the next run loop. It also discusses the two passes the layout engine makes over the view hierarchy and how to interact with the layout engine using methods like updateViewConstraints
and layoutSubviews
.
Thanks for reading
If you enjoyed this post, be sure to follow me on Twitter to keep up with the new content.