UIScrollView
AutoLayout
iOS Development
Constraints
Swift Programming

How can I use Autolayout to set constraints on my UIScrollview?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

UIScrollView works with Auto Layout, but only if you constrain the right things to the right guides. The clean modern pattern is to pin the scroll view to its parent, place a content view inside it, pin that content view to the scroll view's contentLayoutGuide, and then constrain the content view's width or height to the frameLayoutGuide depending on the scroll direction.

The Key Mental Model

With UIScrollView, there are really two layout concerns:

  • the visible frame of the scroll view
  • the size of the scrollable content

Auto Layout handles those through two guides:

  • 'frameLayoutGuide for the visible viewport'
  • 'contentLayoutGuide for the scrollable content area'

If you mix those up, the scroll view either will not scroll or will produce ambiguous constraints.

Vertical Scrolling Setup

For a vertically scrolling layout, the common setup is:

  1. constrain the scroll view to the parent view
  2. add a contentView inside the scroll view
  3. pin contentView on all four sides to contentLayoutGuide
  4. make contentView.widthAnchor equal to frameLayoutGuide.widthAnchor

That last width constraint is what prevents unwanted horizontal scrolling while still allowing vertical expansion.

Programmatic Example

swift
1import UIKit
2
3final class ProfileViewController: UIViewController {
4    private let scrollView = UIScrollView()
5    private let contentView = UIView()
6
7    override func viewDidLoad() {
8        super.viewDidLoad()
9        view.backgroundColor = .systemBackground
10
11        scrollView.translatesAutoresizingMaskIntoConstraints = false
12        contentView.translatesAutoresizingMaskIntoConstraints = false
13
14        view.addSubview(scrollView)
15        scrollView.addSubview(contentView)
16
17        NSLayoutConstraint.activate([
18            scrollView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
19            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
20            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
21            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
22
23            contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
24            contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
25            contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
26            contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
27
28            contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
29        ])
30    }
31}

At this point, the scroll view still needs content inside contentView whose constraints define the content height. That is what gives the scroll view something to scroll.

Content Must Define Its Own Size

The scroll view does not guess content size from nowhere. The subviews inside contentView must fully constrain the content from top to bottom.

Example with a vertical stack:

swift
1let stack = UIStackView()
2stack.axis = .vertical
3stack.spacing = 16
4stack.translatesAutoresizingMaskIntoConstraints = false
5
6contentView.addSubview(stack)
7
8NSLayoutConstraint.activate([
9    stack.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
10    stack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
11    stack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
12    stack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20)
13])

The bottom anchor is crucial. Without it, Auto Layout may not know the final content height.

Interface Builder Version

In Interface Builder, the same logic applies:

  • constrain the scroll view to the parent view
  • add one content view inside the scroll view
  • pin the content view to the content layout guide
  • equalize content view width to the frame layout guide for vertical scrolling

Older tutorials often refer to manually setting contentSize. That is not the preferred approach when using Auto Layout correctly.

Horizontal or Two-Directional Scrolling

If you want horizontal scrolling instead, constrain the content view height to the frame layout guide and let width grow from content. For two-direction scrolling, you usually omit those equal-width or equal-height constraints and instead fully define the content size in both dimensions through subview constraints.

The rule is consistent:

  • lock the non-scrolling axis to the frame
  • let the scrolling axis be determined by content

Common Pitfalls

  • Pinning the content view to the scroll view itself instead of using contentLayoutGuide and frameLayoutGuide.
  • Forgetting the equal-width constraint for vertical scrolling, which often causes unwanted horizontal scrolling or ambiguous layout.
  • Building the content subviews without a bottom constraint, leaving Auto Layout unable to infer the content height.
  • Mixing manual contentSize updates with Auto Layout constraints, which usually creates confusion and conflicting layout logic.
  • Assuming the scroll view will scroll just because subviews exist inside it. The constraints must define a content area larger than the visible frame.

Summary

  • Use contentLayoutGuide for scrollable content edges and frameLayoutGuide for the visible viewport.
  • For vertical scrolling, pin the content view to the content guide and match its width to the frame guide.
  • Make sure the inner content is fully constrained from top to bottom so Auto Layout can infer the content height.
  • The same idea works in both code and Interface Builder.
  • If the constraints correctly define the content size, you usually do not need to set contentSize manually.

Course illustration
Course illustration

All Rights Reserved.