← Back to list

Understanding setNeedsLayout, updateConstraints, and layoutSubviews in iOS

When building dynamic interfaces in UIKit, you often need to trigger layout updates or adjust subviews when the view’s size or state…

Mobile Engineering: Build, Lead, Deliver · 2025-11-27 09:17 · 0 claps · 3.2 min read
#swift-programming #uikit #ios-development #clean-code-architecture #mobile-development
Open on Medium ↗
Wiki topics: 💻 · Programming 📱 · Mobile Development 🏛️ · Architecture

Understanding setNeedsLayout, updateConstraints, and layoutSubviews in iOS

When building dynamic interfaces in UIKit, you often need to trigger layout updates or adjust subviews when the view’s size or state changes. Three important methods appear frequently in this workflow:

  • **setNeedsLayout()**
  • **updateConstraints()**
  • **layoutSubviews()**

Although they belong to the same layout system, each method plays a distinct role at a different stage of the UIKit layout cycle. Understanding what each method does, when it is called, and how they interact is essential for writing reliable UI code.

This article explains each method clearly and in order.

UIKit’s Layout Cycle Overview

Whenever something changes in your interface — like constraints, view sizes, or device orientation — UIKit performs a layout pass.

This layout pass consists of three major phases:

  1. Constraint Update Phase UIKit updates Auto Layout constraints. Method involved: updateConstraints()
  2. Layout Phase UIKit calculates and assigns frames to subviews. Method involved: layoutSubviews()
  3. Drawing Phase UIKit renders the view hierarchy on the screen. Method involved: draw(_:)

The three methods you use (setNeedsLayout, updateConstraints, layoutSubviews) participate in the first two phases only.

1. updateConstraints()

Purpose

updateConstraints() is responsible for installing or updating Auto Layout constraints.

This is the earliest method in the layout sequence that UIKit calls when constraints need to be updated. You override it when constraints change based on dynamic state.

When UIKit Calls It

UIKit calls updateConstraints() when:

  • Constraints have changed
  • You call setNeedsUpdateConstraints()
  • A system-triggered layout pass occurs (rotation, text size change)
  • Subviews are added or removed
  • A constraint’s constant changes

Important: This method is not called on every layout pass — only when constraints have become invalid.

What You Do Inside It

You override it to activate, deactivate, or modify constraints.

Example:

override func updateConstraints() {
    if isExpanded {
        expandedConstraints.forEach { $0.isActive = true }
        collapsedConstraints.forEach { $0.isActive = false }
    } else {
        collapsedConstraints.forEach { $0.isActive = true }
        expandedConstraints.forEach { $0.isActive = false }
    }
  super.updateConstraints()
}

What You Should NOT Do

  • Do not change frames
  • Do not perform animations
  • Do not add subviews

updateConstraints() is strictly for constraint changes.

2. setNeedsLayout()

Purpose

setNeedsLayout() tells UIKit:

“This view’s layout may be outdated. Please schedule a layout update.”

It does not perform layout immediately. It only marks the view as needing layout, and UIKit will handle it on the next run loop.

When You Call It

You call setNeedsLayout() when something changes that affects how subviews should be arranged. Examples:

  • A property changes that affects layout
  • A label gets new text
  • Internal state changes (expanded/collapsed)
  • You update the UI and want subviews to reposition
setNeedsLayout()

If you want layout immediately, you use:

layoutIfNeeded()

When UIKit Calls It Automatically

UIKit automatically triggers setNeedsLayout() when:

  • Constraints change
  • View frame or bounds change
  • Adding/removing subviews
  • Device orientation changes
  • Intrinsic content size changes

3. layoutSubviews()

Purpose

layoutSubviews() is where UIKit performs the actual layout of the view.

This is the primary method you override when writing custom layout code.

Inside it, you position and size your view’s subviews based on:

  • Resolved Auto Layout constraints
  • intrinsicContentSize
  • Manual frame calculations

When UIKit Calls It

UIKit invokes layoutSubviews() when:

  • A layout pass occurs
  • After constraints are updated
  • The view’s bounds change
  • setNeedsLayout() was called
  • layoutIfNeeded() forces immediate layout
  • Device orientation changes
  • A subview is added or removed

What You Do Inside It

You update frames, adjust sizes, or make layout-related calculations.

Example:

override func layoutSubviews() {
    super.layoutSubviews()
    titleLabel.frame = CGRect(
        x: 20,
        y: 20,
        width: bounds.width - 40,
        height: 30
    )
}

If Auto Layout is used, you typically only perform final adjustments here.

How They Work Together

Here is the exact order of events during a layout update:

  1. Something changes that affects layout You or the system triggers setNeedsLayout().
  2. UIKit schedules a layout pass It does not run immediately unless forced.
  3. UIKit checks constraints Calls updateConstraints() if needed (Only if constraints are invalid or updated.)
  4. Constraints are resolved internally Sizes and positions are calculated.
  5. UIKit applies layout Calls layoutSubviews().
  6. Views are drawn Calls draw(_:).

This flow ensures constraints and layout remain synchronized.

Comparison Table

MethodPhaseCalled ByWhat It DoesDeveloper UseupdateConstraints()Constraint Update PhaseUIKitUpdates Auto Layout constraintsModify or toggle constraintssetNeedsLayout()Pre-layout triggerDeveloper / UIKitSchedules a layout passNotify that layout must updatelayoutSubviews()Layout PhaseUIKitApplies frames to subviewsCustom frame layout or final adjustments

Practical Example

Here’s a custom view that updates constraints when expanded and triggers layout updates properly.

class CustomView: UIView {
  private let box = UIView()
    var isExpanded = false
    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubview(box)
        box.backgroundColor = .red
    }
    required init?(coder: NSCoder) { fatalError() }
    override func updateConstraints() {
        if isExpanded {
            heightConstraint.constant = 200
        } else {
            heightConstraint.constant = 80
        }
        super.updateConstraints()
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        box.frame = bounds.insetBy(dx: 10, dy: 10)
    }
    func toggle() {
        isExpanded.toggle()
        setNeedsUpdateConstraints()   // Constraints must recalc
        setNeedsLayout()              // Layout must rerun
    }
}

Final Thoughts

These three methods serve different purposes within UIKit’s layout pipeline:

  • updateConstraints() updates the rules
  • layoutSubviews() applies the layout
  • setNeedsLayout() triggers the rerun of layout

Because each one participates at a different point in the layout cycle, using them correctly prevents layout glitches, unnecessary work, and inconsistent UI behavior.


메타데이터
post_id
bdd3eda042ca
slug
understanding-setneedslayout-updateconstraints-and-layoutsubviews-in-ios-bdd3eda042ca
url
https://medium.com/@bharathibala21/understanding-setneedslayout-updateconstraints-and-layoutsubviews-in-ios-bdd3eda042ca
canonical_url
https://medium.com/@bharathibala21/understanding-setneedslayout-updateconstraints-and-layoutsubviews-in-ios-bdd3eda042ca
author_url
https://medium.com/@bharathibala21
status
ok
fetched_at
2026-08-08 16:47:33