Mobile Development

View Layout

iOS defines where views will be placed on screen with a system called Auto Layout.

Auto Layout is a system that lets you lay out your app’s user interface by creating a mathematical description of the relationships between the elements. You define these relationships in terms of constraints either on individual elements, or between sets of elements. [1]

Auto Layout is a term used to describe how iOS will dynamically adjust the various views of your app. View layout can be configured through a variety different ways, all of which will be described in detail below.

This chapter will be covering:

  1. Definitions
  2. Springs and Struts
  3. Interface Builder
  4. Auto Layout From Code

Definitions

Let's frame our material with definitions for terms encountered when talking about Auto Layout.

  • Constraints - A constraint is a mathematical representation of a human-expressable statement. [2]
    • Constant - The physical size or offset, in points, of the constraint. [2]
    • Relation - You can use relations and inequalities such as greater-than-or-equal to define constraints. [2]
    • Priority - Constraints with higher priority levels are satisfied before constraints with lower priority levels. [2]
    • Multiplier
  • Content - Content refers to the data being displayed in your label, button or view.
    • Hugging - Defines how a view will hug its contents when resized.
    • Content Compression - Defines how a view will compress the content of its view when resized.
    • Intrinsic Size - Content knows its size better than its containing view. A UILabel that has dynamic text will know its size better than its containing view.

Each term will be expanded upon in detail below.

Springs and Struts

Before we continue, let's quickly talk about springs and structs. Springs and struts where the common way of laying out views until iOS 7. Springs and struts are also known as autoresizing masks.

A flexible width the view will become proportionally wider if the superview also becomes wider. And with a fixed right margin, the view’s right edge will always stick to the superview’s right edge.

iOS development has moved beyond Springs and Struts since iOS7.

The [springs and struts] system works well for simple cases, but it quickly breaks down when your layouts become more intricate.

Once Apple began selling devices in multiple sizes, Auto Layout became indispensable.

Next step, getting started with Auto Layout.

Overview of Auto Layout in IB

It is easiest to begin in Interface Builder when configuring Auto Layout in your mobile app. Below shows a configured view as seen in Document Outline:

The output of these constraints can be seen in on the iPhone in both orientations:

Next, we will watch a video demonstrating the process of setting up constraints in a mobile app.

[Video] Building Adaptive Layouts with UIKit

Apple gave an excellent talk at WWDC 2014 on adaptive Layouts. In this video, Apple engineers talk about how and why to make your views adaptive using Auto Layout:

ITC 1 of 2

https://developer.apple.com/videos/play/wwdc2014-216

Advanced: Size Classes

The above video briefly covered size classes. Size classes are used to define layouts for particular devices. Best practices are to keep one layout across all devices and move to more specific size classes only when necessary.

Source [4]

Further information on Size Classes can be found here: https://developer.apple.com/library/ios/recipes/xcode_help-IB_adaptive_sizes/chapters/AboutAdaptiveSizeDesign.html

Overview of Auto Layout in Code

There are two ways to control Auto Layout through code. Those are:

  1. NSLayoutConstraints
  2. Visual Format Language

We will go into each in detail now.

NSLayoutConstraints

NSLayoutConstraints can have associated IBOutlets within your implementation file. They can also be generated and attached within code.

First, an example of controlling a constraint by qualifying it with an IBOutlet, connecting it in Xcode and controlling the constant in code:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak private var bottomConstraint: NSLayoutConstraint!

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        bottomConstraint.constant = -8
    }
}

This is pretty powerful in that you can animate and dynamically resize views based on constraints instead of geometry.

Next, you can also add constraints directly to views within code, without the need for Interface Builder. The following code creates an UIView, adds it as a subview and attaches constraints in order to create a 10 pixel border.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak private var containerView: UIView!

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        var innerView = UIView()
        innerView.backgroundColor = UIColor.greenColor()
        containerView.addSubview(innerView)

        innerView.setTranslatesAutoresizingMaskIntoConstraints(false)
        let constraintTop = NSLayoutConstraint(item: innerView, attribute: .Top, relatedBy: .Equal, toItem: containerView, attribute: .Top, multiplier: 1.0, constant: 10)
        let constraintRight = NSLayoutConstraint(item: innerView, attribute: .Trailing, relatedBy: .Equal, toItem: containerView, attribute: .Trailing, multiplier: 1.0, constant: -10)
        let constraintBottom = NSLayoutConstraint(item: innerView, attribute: .Bottom, relatedBy: .Equal, toItem: containerView, attribute: .Bottom, multiplier: 1.0, constant: -10)
        let constraintLeft = NSLayoutConstraint(item: innerView, attribute: .Leading, relatedBy: .Equal, toItem: containerView, attribute: .Leading, multiplier: 1.0, constant: 10)
        containerView.addConstraints([constraintTop, constraintRight, constraintBottom, constraintLeft])
        containerView.layoutIfNeeded()
    }
}

The output of the above code will then be:

The following tutorial expands on the concept of adding constriants in Swift with several examples:

http://www.ioscreator.com/tutorials/auto-layout-in-ios-6-adding-constraints-through-code

Visual Format Language

VFL is an advanced topic that we will mention here and encourage you to explore deeper once the other methods of Auto Layout have been tackled.

The next code example translates the previous NSLayoutConstraint code into VFL, which produces the same result as above:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak private var containerView: UIView!

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        var innerView = UIView()
        innerView.backgroundColor = UIColor.greenColor()
        containerView.addSubview(innerView)

        innerView.setTranslatesAutoresizingMaskIntoConstraints(false)
        let views = Dictionary(dictionaryLiteral: ("inner", innerView))
        let horiz = NSLayoutConstraint.constraintsWithVisualFormat("H:|-10.0-[inner]-10.0-|", options: nil, metrics: nil, views: views)
        let vert = NSLayoutConstraint.constraintsWithVisualFormat("V:|-10.0-[inner]-10.0-|", options: nil, metrics: nil, views: views)
        containerView.addConstraints(horiz)
        containerView.addConstraints(vert)
    }
}

For further step-by-step tutorials and instruction in VFL, please check out the following two resouces:

  1. http://nsscreencast.com/episodes/134-visual-format-language
  2. http://commandshift.co.uk/blog/2013/01/31/visual-format-language-for-autolayout/

Handling Warnings & Errors

Auto layout is very specific. Constraints must be understood by iOS in order to function.

Auto Layout issues occur when you create conflicting constraints, when you don’t provide enough constraints, or when the final layout contains a set of constraints that are ambiguous.

The two most common AL problems are

  1. Build Errors - Conflicting constraints in IB, which will show a red warning indicator and
  2. Runtime Exceptions - Fatal exceptions in the runtime due to unsatisfiable constraints created in code.

To resolve Auto Layout issues, walk through the code and constraints individually. You can always clear all existing constraints and rebuild them. Each added constraint should be purposed, if you can leave out a constraint, do so.

Apple provides two guides for resolving Auto Layout issues:

  1. https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/TypesofErrors.html#//apple_ref/doc/uid/TP40010853-CH17-SW1
  2. https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/DebuggingTricksandTips.html#//apple_ref/doc/uid/TP40010853-CH21-SW1

Xcode provides the ability to attempt and automatically resolve Auto Layout issues for you, when working with Interface Builder. Generally speaking, spend the extra time and resolve the issues yourself. The more experience you have with Auto Layout, the easier it will be to create accurate constraints in the future.

Reference

[1] Auto Layout Guide https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/index.html#//apple_ref/doc/uid/TP40010853-CH7-SW1

[2] Beginning Auto Layout http://www.raywenderlich.com/20881/beginning-auto-layout-part-1-of-2

[3] iOS 8 Development Tips https://medium.com/@getaaron/ios-8-development-tips-for-iphone-6-and-iwatch-1c772554ffe0

[4] NSLayoutConstraints https://developer.apple.com/library/prerelease/ios/documentation/AppKit/Reference/NSLayoutConstraint_Class/index.html

[5] Visual Format Language https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage.html