Learning Auto Layout without using Storyboards in Swift

My goal in this tutorial is to create views using constraints. I will try to use it in such a way that, anyone can use these constraints to build a more complex layout. The view I would like to create is similar to a UITableViewCell.

Create a view and place it at the top of the superview. For every view, you need to set translatesAutoresizingMaskIntoConstraints = false otherwise the custom auto layout constraints won’t work.

override func viewDidLoad() {
    super.viewDidLoad()
    let roundView = UIView()
    roundView.backgroundColor = .purple
    roundView.translatesAutoresizingMaskIntoConstraints = false
    roundView.layer.cornerRadius = 50
    view.addSubview(roundView)
    view.backgroundColor = .yellow

    let margins = view.layoutMarginsGuide
    roundView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
    roundView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0.0).isActive = true
    roundView.heightAnchor.constraint(equalToConstant: 100).isActive = true
    roundView.widthAnchor.constraint(equalToConstant: 100).isActive = true
}

If your view is the top most view, make use of the safeAreaLayoutGuide to help with safe area insets. roundView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0.0).isActive = true If you don’t use this, then your view will get clipped.

Move the view to the bottom of the screen. Let’s make use of the bottomAnchor constraint. Use the code below.

let margins = view.layoutMarginsGuide
roundView.leadingAnchor.constraint(equalTo:margins.leadingAnchor).isActive = true
roundView.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor, constant: 0.0).isActive = true
roundView.heightAnchor.constraint(equalToConstant: 100).isActive = true
roundView.widthAnchor.constraint(equalToConstant: 100).isActive = true

Map the view to center of the screen.

roundView.centerXAnchor.constraint(equalTo:margins.centerXAnchor).isActive = true
roundView.centerYAnchor.constraint(equalTo:margins.centerYAnchor).isActive = true

Move the view to the right side of the screen.

roundView.trailingAnchor.constraint(equalTo:view.safeAreaLayoutGuide.trailingAnchor, constant: 0.0).isActive = true

Add a label to the right of the view. Let’s call it the title label.

let margins = view.layoutMarginsGuide
// set the height and width
roundView.heightAnchor.constraint(equalToConstant: 100).isActive = true
roundView.widthAnchor.constraint(equalToConstant: 100).isActive = true

// set the position to the top most of the screen
roundView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
roundView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10.0).isActive = true

// add another label to right of the round view
let title = UILabel()
title.translatesAutoresizingMaskIntoConstraints = false
title.text = "This is the title"
view.addSubview(title)
title.heightAnchor.constraint(equalToConstant: 40).isActive = true
title.backgroundColor = .red
title.leadingAnchor.constraint(equalTo: roundView.trailingAnchor, constant: 10).isActive = true
title.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: 10).isActive = true
title.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10.0).isActive = true

Let’s add a subtitle to the view

let subtitle = UILabel()
subtitle.translatesAutoresizingMaskIntoConstraints = false
subtitle.text = "This is the subtitle"
view.addSubview(subtitle)
subtitle.heightAnchor.constraint(equalToConstant: 40).isActive = true
subtitle.backgroundColor = .brown
subtitle.leadingAnchor.constraint(equalTo: roundView.trailingAnchor, constant: 10).isActive = true
subtitle.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 10).isActive = true
subtitle.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: 10).isActive = true

The magic of using AutoLayout. It will work automatically for Right to left languages and also different orientations, as shown below.

Moving on, let’s consider you want to manage both regular and compact views in your code. You can use an array of NSLayoutConstraints and manage the views accordingly. I will be showing you how this can be done for a compact view. Try doing the same for a regular view. It’s pretty straight forward. The entire code base is as shown below.

import UIKit

class ViewController: UIViewController {

	var regularConstraints = [NSLayoutConstraint]()
	var compactConstraints = [NSLayoutConstraint]()
	
	private func enableConstraintsForWidth(horizontalSizeClass: UIUserInterfaceSizeClass) {
	  if horizontalSizeClass == .regular {
		NSLayoutConstraint.deactivate(compactConstraints)
		NSLayoutConstraint.activate(regularConstraints)
	  } else {
		NSLayoutConstraint.deactivate(regularConstraints)
		NSLayoutConstraint.activate(compactConstraints)
	  }
	}
	
	override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
		super.traitCollectionDidChange(previousTraitCollection)
	  if traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass {
		enableConstraintsForWidth(horizontalSizeClass: traitCollection.horizontalSizeClass)
	  }
	}

	
	override func viewDidLoad() {
		super.viewDidLoad()
		// Do any additional setup after loading the view.
		let roundView = UIView()
		roundView.backgroundColor = .purple
		roundView.translatesAutoresizingMaskIntoConstraints = false
		roundView.layer.cornerRadius = 50
		view.addSubview(roundView)
		view.backgroundColor = .yellow
		
		let margins = view.layoutMarginsGuide
		// set the height and width
		roundView.heightAnchor.constraint(equalToConstant: 100).isActive = true
		roundView.widthAnchor.constraint(equalToConstant: 100).isActive = true

		// set the position to the top most of the screen
		compactConstraints.append(roundView.leadingAnchor.constraint(equalTo: margins.leadingAnchor))
		compactConstraints.append(roundView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10.0))
		
		// add another label to right of the round view
		let title = UILabel()
		title.translatesAutoresizingMaskIntoConstraints = false
		title.text = "This is the title"
		view.addSubview(title)
		compactConstraints.append(title.heightAnchor.constraint(equalToConstant: 40))
		title.backgroundColor = .red
		compactConstraints.append(title.leadingAnchor.constraint(equalTo: roundView.trailingAnchor, constant: 10))
		compactConstraints.append(title.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: 10))
		compactConstraints.append(title.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10.0))
		
		let subtitle = UILabel()
		subtitle.translatesAutoresizingMaskIntoConstraints = false
		subtitle.text = "This is the subtitle"
		view.addSubview(subtitle)
		subtitle.heightAnchor.constraint(equalToConstant: 40).isActive = true
		subtitle.backgroundColor = .brown
		compactConstraints.append(subtitle.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 10.0))
		compactConstraints.append(subtitle.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: 10))
		compactConstraints.append(subtitle.leadingAnchor.constraint(equalTo: title.leadingAnchor, constant: 10.0))
		if self.traitCollection.horizontalSizeClass != .regular {
			enableConstraintsForWidth(horizontalSizeClass: traitCollection.horizontalSizeClass)
		}

	}

}

One response

  1. […] Before starting this article, please try read through this article which has a good tutorial on using auto layout constraints. https://redflowerinc.com/learning-auto-layout-without-using-storyboards-in-swift/ […]

Leave a Reply

Your email address will not be published. Required fields are marked *