Auto Layout is Apple's adaptive interface element positioning system, based on mathematical constraints. Developed for iOS 6 (2012), Auto Layout allows you to create interfaces that display correctly on all devices — from iPhone SE (4.7″) to iPad Pro (12.9″) and Dynamic Island. According to Apple WWDC Session 202 (2024), more than 90% of apps in the App Store use Auto Layout or its declarative alternative — SwiftUI layout system. Constraints describe dependencies between UI elements through linear equations: view1.leading = view2.trailing + 8.
Key Takeaways
Auto Layout is Apple's adaptive layout system that uses mathematical constraints for positioning UI elements. Unlike frame-based layout, where each element has fixed x, y, width, height coordinates, Auto Layout describes relationships between elements: "the button is 8pt from the parent's right edge" or "the text field width equals half the screen width." The mechanism is based on the Cassowary algorithm, developed at the University of Washington (Greg J. Badros, 1999) and implemented by Apple in iOS 6. Cassowary solves a system of linear inequalities with priorities — Required (1000), Default High (750), Default Low (250) — allowing constraint conflict management. Auto Layout supports three size types: intrinsic (the element's natural size determined by content), explicit (explicitly set constraint), and compressible/stretchable (rubber mode via Content Hugging Priority and Compression Resistance Priority).
Each UI element in Auto Layout has an Intrinsic Content Size — a natural size determined by its content. For UILabel this depends on text and font, for UIImageView — on image dimensions. Content Hugging Priority (resistance to stretching) and Compression Resistance Priority (resistance to compression) control element behavior when available space changes. Standard values: 251 for hugging and 749 for compression resistance. If two elements compete for space, priority determines which one stretches first. Understanding these priorities is key to resolving Ambiguous Layout, which Xcode highlights in the debugger.
A constraint is described by the equation: view1.attribute = multiplier × view2.attribute + constant. Attributes include leading, trailing, top, bottom, centerX, centerY, width, height, firstBaseline, lastBaseline. Multiplier is used for proportional relationships (view1 width = 0.5 × superview width). Constant sets a fixed offset (leading = superview.leading + 16). Interface Builder tools allow visual constraint creation via Ctrl-drag, but complex layouts require programmatic creation through NSLayoutConstraint or VFL (Visual Format Language), which Apple recommends replacing with NSLayoutConstraint since iOS 9.
The constraints system is solved as a linear programming problem: the Cassowary algorithm finds the optimal arrangement of all elements that satisfies all constraints considering their priorities. If constraints contradict each other, an Unsatisfiable Layout occurs — an exception that Xcode logs with a detailed conflict description. If there are insufficient constraints to determine at least one element's position, an Ambiguous Layout occurs — elements display at arbitrary positions. Apple recommends a minimum set: for each element, position (x, y) and size (width, height) must be set — explicitly or through intrinsic content size. Constraints can be first-class: leading element (e.g., superview) and trailing (child view) create a hierarchy.
Cassowary uses the Sequential Quadratic Programming method to solve systems of linear inequalities. Each constraint has a priority from 1 to 1000. Required (1000) is a mandatory constraint; if it cannot be fulfilled, the app crashes with NSConstraintException. Default High (750) is recommended; Default Low (250) is the least important. During conflict, Cassowary relaxes lower-priority constraints. For example, if two elements require a fixed width but the screen is too narrow, the lower-priority constraint is relaxed. In Xcode Debug View Hierarchy (debugging tool available since Xcode 6) only highlights problems with Required constraints — others are handled without error.
UIStackView is a container introduced in iOS 9 (2015) that automatically creates and manages constraints for nested arrangedSubviews. UIStackView supports two axes: horizontal and vertical. Distribution settings determine space allocation: fill (proportional filling based on hugging priority), fillEqually (equal sizes), fillProportionally (proportional to intrinsic content size), equalSpacing (equal spacing), equalCentering (equal distances between centers). Alignment sets cross-axis alignment: fill, leading, center, trailing (for horizontal) or fill, top, center, bottom (for vertical). UIStackView automatically manages spacing, baseline alignment, and Dynamic Type adaptation.
import UIKit
class StackViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let stack = UIStackView()
stack.axis = NSLayoutConstraint.Axis.vertical
stack.distribution = .fillEqually
stack.spacing = 8
stack.translatesAutoresizingMaskIntoConstraints = false
let label = UILabel()
label.text = "Auto Layout Guide"
label.font = UIFont.preferredFont(forTextStyle: .headline)
let button = UIButton(type: .system)
button.setTitle("Apply", for: .normal)
stack.addArrangedSubview(label)
stack.addArrangedSubview(button)
view.addSubview(stack)
NSLayoutConstraint.activate([
stack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
stack.centerYAnchor.constraint(equalTo: view.centerYAnchor),
stack.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 16),
stack.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -16)
])
}
}The code creates a vertical UIStackView with two elements (UILabel and UIButton), distributed evenly (fillEqually) with 8pt spacing. The stack is centered on screen with margins of at least 16pt from edges. translatesAutoresizingMaskIntoConstraints = false is required when creating constraints programmatically — without it, Auto Layout does not work. At IT Sectr, UIStackView is used in 80% of iOS project screens for building adaptive forms, settings lists, and cards.
UIStackViews can be nested: a horizontal stack inside a vertical one is a standard pattern for complex layouts. The outer stack manages rows, the inner stack manages columns within each row. Combining axis, alignment, and distribution at each level provides virtually unlimited flexibility without a single manual constraint. Apple recommends UIStackView as the primary layout tool in UIKit, resorting to manual NSLayoutConstraint only for cases not covered by stacks: overlapping views, precise pixel positioning, custom bounds animation.
NSLayoutConstraint is a programmatic API for creating individual constraints in code. Each constraint is created via an initializer with parameters: item, attribute, relatedBy, toItem, attribute, multiplier, constant. Since iOS 9, Apple introduced the Anchor API — a more readable syntax through view.leadingAnchor, view.trailingAnchor, view.topAnchor, view.bottomAnchor, view.centerXAnchor, view.centerYAnchor, view.widthAnchor, view.heightAnchor properties. The Anchor API automatically sets relatedBy = .equal and uses First Item/Second Item from Anchors, reducing code by 40% compared to classic NSLayoutConstraint.
import UIKit
class ConstraintViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let childView = UIView()
childView.backgroundColor = .systemBlue
childView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(childView)
NSLayoutConstraint.activate([
childView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 24),
childView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
childView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
childView.heightAnchor.constraint(equalToConstant: 120),
childView.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -24)
])
}
}The code positions childView with margins from safeAreaLayoutGuide (top) and screen edges (leading/trailing). lessThanOrEqualTo for bottom ensures the view does not exceed the bottom boundary. The Anchor API throws a compile-time exception if anchors are incompatible (e.g., leadingAnchor mixed with rightAnchor), preventing runtime errors. Apple recommends the Anchor API as the standard for programmatic Auto Layout since iOS 9.
Safe Area is the screen area not overlapped by system elements: Dynamic Island, Notch, Status Bar, Home Indicator, rounded corners. In iOS 11, Apple replaced topLayoutGuide/bottomLayoutGuide with safeAreaLayoutGuide, which automatically adapts to device orientation and screen cutout presence. Layout Margins are default internal view insets (16pt on iOS, 20pt on iPadOS). For UILayoutGuide you can set custom directionalLayoutMargins considering RIGHT-TO-LEFT localization. Auto Layout automatically respects safe area when using safeAreaLayoutGuide in anchors.
On devices with Dynamic Island (iPhone 14 Pro and newer) and Notch (iPhone X–13), Safe Area excludes 44pt at the top in portrait (59pt with Dynamic Island when active). Home Indicator adds 34pt at the bottom. For correct adaptation, all top constraints should be attached to safeAreaLayoutGuide.topAnchor, not view.topAnchor. Bottom constraints should be attached to safeAreaLayoutGuide.bottomAnchor or view.bottomAnchor with a margin for Home Indicator. At IT Sectr, we test all screens on iPhone SE (2022), iPhone 14 Pro Max and iPad Pro 12.9″ simulators — three devices covering all safe area variations.
The most frequent errors when working with Auto Layout: forgotten translatesAutoresizingMaskIntoConstraints = false, conflicting Required constraints (priority 1000), Ambiguous Layout (insufficient constraints to determine position), incorrect Content Hugging Priority for multi-line UILabel, and mixing leading/trailing with left/right anchors. Xcode 15+ displays layout issues in the Runtime Issue Navigator and offers automatic fixes. For complex layouts, use Debug View Hierarchy: yellow markers indicate ambiguous layout, red ones indicate unsatisfiable.
| Error | Cause | Solution |
|---|---|---|
| translatesAutoresizingMaskIntoConstraints = true | Auto Layout not activated for view | Set false for all programmatic views |
| Unsatisfiable Layout | Conflict of Required (1000) constraints | Lower one priority to Default High (750) |
| Ambiguous Layout | Insufficient constraints for x/y/w/h | Add missing constraint or check intrinsic size |
| Text truncation in UILabel | Content Hugging Priority lower than competitor | Raise hugging priority to 252+ |
| Mixing LTR/RTL anchors | leadingAnchor with rightAnchor | Use only leading/trailing for RTL support |
Frequently Asked Questions
Frame-based layout sets fixed x, y, width, height coordinates for each element. Auto Layout uses mathematical constraints — relationships between elements: "label.leading = button.trailing + 8". Frame-based layout does not adapt to screen size; Auto Layout automatically recalculates positions on rotation, Split View, or Dynamic Type changes.
UIStackView is optimal for linear layouts: rows, columns, forms, parameter lists. NSLayoutConstraint is needed for overlapping views, precise pixel positioning, custom bounds animation, and cases where space distribution is uneven and not covered by UIStackView distribution. In practice, 80% of layouts are solved with UIStackView, 20% with manual constraints.
Content Hugging Priority (resistance to stretching) is a priority that determines how much an element resists increasing its size beyond the Intrinsic Content Size. Default value is 251. If two elements compete for free space, the element with higher hugging priority stays its size while the second stretches. Compression Resistance Priority (749 by default) works similarly for compression.
Auto Layout automatically adapts to Dynamic Type if constraints use the intrinsic content size of labels. When font size increases, UILabel expands, shifting neighboring elements through constraints. UIStackView with distribution = fillProportionally redistributes space proportionally to new intrinsic sizes. Safe Area and Layout Margins also respect accessibility settings.
Unsatisfiable Layout occurs when two Required (priority = 1000) constraints contradict each other: for example, view.leading = superview.leading + 16 and view.trailing = superview.leading + 200 with a superview width of 100pt. The Cassowary algorithm cannot find a solution, and the app crashes with NSConstraintException. The solution is to lower the priority of one of the conflicting constraints to Default High (750).
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also