Swift
iOS Development
Auto Layout
Constraints
Programming Tutorial

How to add constraints programmatically using Swift

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Programmatic Auto Layout is the right tool when views are created dynamically, reused across screens, or difficult to express cleanly in Interface Builder. The main idea is simple: create the view, disable autoresizing-mask translation, add it to the hierarchy, and then activate a small set of constraints that clearly describe the layout contract.

Start With Anchors and translatesAutoresizingMaskIntoConstraints

The most important setup line is usually this one:

swift
let cardView = UIView()
cardView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(cardView)

If you forget it, UIKit creates constraints from the view's autoresizing mask and those often conflict with the constraints you add manually.

After that, use anchor-based constraints as the default style:

swift
1NSLayoutConstraint.activate([
2    cardView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
3    cardView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
4    cardView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
5    cardView.heightAnchor.constraint(equalToConstant: 120)
6])

Anchor APIs are easier to read than older factory-style NSLayoutConstraint initializers, and they give compile-time help by separating horizontal, vertical, and dimension anchors.

Use Safe Areas and Meaningful Containers

A common early mistake is pinning everything to the raw edges of the root view. On modern devices, safe areas usually describe the visible and usable content region much better.

swift
1let titleLabel = UILabel()
2let bodyLabel = UILabel()
3
4titleLabel.translatesAutoresizingMaskIntoConstraints = false
5bodyLabel.translatesAutoresizingMaskIntoConstraints = false
6
7view.addSubview(titleLabel)
8view.addSubview(bodyLabel)
9
10let safe = view.safeAreaLayoutGuide
11
12NSLayoutConstraint.activate([
13    titleLabel.topAnchor.constraint(equalTo: safe.topAnchor, constant: 24),
14    titleLabel.leadingAnchor.constraint(equalTo: safe.leadingAnchor, constant: 20),
15    titleLabel.trailingAnchor.constraint(equalTo: safe.trailingAnchor, constant: -20),
16
17    bodyLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 12),
18    bodyLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
19    bodyLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor)
20])

As layouts grow, it is usually cleaner to constrain groups of views inside container views or stack views than to create a dense web of cross-screen constraints.

Prefer Flexible Layouts Over Hardcoded Sizes

Fixed heights are easy to write and easy to regret. Text size, localization, and device size changes all punish rigid layouts.

When possible, let labels and controls use intrinsic content size. For views that need bounds, use minimums, maximums, or priorities instead of only hard constants.

swift
1let imageView = UIImageView()
2imageView.translatesAutoresizingMaskIntoConstraints = false
3view.addSubview(imageView)
4
5let minHeight = imageView.heightAnchor.constraint(greaterThanOrEqualToConstant: 100)
6minHeight.priority = .defaultHigh
7
8let preferredHeight = imageView.heightAnchor.constraint(equalToConstant: 180)
9preferredHeight.priority = .defaultLow
10
11NSLayoutConstraint.activate([
12    imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
13    imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
14    minHeight,
15    preferredHeight
16])

This gives Auto Layout room to adapt instead of forcing impossible layouts when space is tight.

Store Only the Constraints You Need to Change

Most constraints can stay inside one activation block and never be referenced again. Keep a property only for constraints that will change later, such as keyboard adjustments, expansion panels, or animated position changes.

swift
1final class ExpandViewController: UIViewController {
2    private let panel = UIView()
3    private var topConstraint: NSLayoutConstraint!
4
5    override func viewDidLoad() {
6        super.viewDidLoad()
7
8        panel.translatesAutoresizingMaskIntoConstraints = false
9        view.addSubview(panel)
10
11        topConstraint = panel.topAnchor.constraint(
12            equalTo: view.safeAreaLayoutGuide.topAnchor,
13            constant: 20
14        )
15
16        NSLayoutConstraint.activate([
17            topConstraint,
18            panel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
19            panel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
20            panel.heightAnchor.constraint(equalToConstant: 100)
21        ])
22    }
23
24    func expandPanel() {
25        topConstraint.constant = 80
26        UIView.animate(withDuration: 0.25) {
27            self.view.layoutIfNeeded()
28        }
29    }
30}

Notice that the animation updates an existing constraint. It does not create a new conflicting one.

Debug Constraint Problems Methodically

When Auto Layout breaks, do not guess. Check these in order:

  1. Was translatesAutoresizingMaskIntoConstraints disabled
  2. Is the view already in the hierarchy before constraining it
  3. Are there enough constraints to determine size and position
  4. Are there conflicting fixed sizes with no flexible alternative
  5. Do the console logs name one unsatisfiable constraint chain

Constraint bugs get easier when layout code lives in a dedicated setup method called once. Recreating constraints in viewDidLayoutSubviews or scattering them across unrelated callbacks makes conflicts harder to reason about.

Common Pitfalls

The most common mistake is forgetting to set translatesAutoresizingMaskIntoConstraints = false before adding manual constraints.

Another frequent issue is over-constraining a view with too many fixed constants. Developers also often pin to raw screen edges when they should use safe areas, or they create new constraints every time the UI changes instead of updating the constants on existing ones.

Summary

  • Disable autoresizing-mask translation on views you constrain manually.
  • Use anchor-based constraints as the default Auto Layout style in Swift.
  • Prefer safe areas and container-based layout structure over raw edge pinning.
  • Use priorities and flexible dimensions instead of hardcoding every size.
  • Keep references only to constraints you plan to update later.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.