In this post we will apply constraints to 4 views in a NSWindow using swift NSLayoutConstraint programatically. This approach is much more tedious and lengthy in comparison to the constraintsWithVisualFormat Approach.
Its upto the developers discretion to either use the visual format or constrain initializer approach.
Note: The autoLayOut checkbox is switched off in the XIB and all the constraints will be added programmatically
In the below sample the following behaviour is desired
Red View – Header and is of constant height- width is resizable as the window resizes
Green View – Search Section is of constant height – width of the green view increases as the window resizes
Blue View – Data View is of dynamic width and height and increases as the screen resizes.
Cyan View – Footer section is of fixed height and dynamic width
The screen has a minimum width and height that is derived from the sections
Before applying constraint
Swift NSLayoutConstraint constraintsWithVisualFormat- after applying constraints programmatically
The use of hidden spacer or dummy views is a common technique with auto layout when you need to set constraints on a rectangular space in the view. They allow you to control the spacing between views or to group related objects.
The disadvantage is that they are still real views in the view hierarchy consuming memory and able to respond to messages in the responder chain. Apple added the UILayoutGuide class in iOS 9 to do the same job as spacer or dummy views without the overhead.
Equally Spaced Buttons
Let’s look at a common use for spacer views. Suppose we have two buttons that we want to be evenly spaced horizontally:
The two buttons have a fixed width set to fit the longest title. The spacing is evenly distributed between each button and the margins of the superview. The width of these spaces changes as the superview changes (e.g. on rotation) but are always equal to each other.
Since you cannot set constraints on empty space it is common to add dummy spacer views where we want the space. Here is the same screenshot with the space between the buttons and margins made visible so you can see what is going on:
If you are supporting iOS 8 or earlier the easiest way to create this layout is to add three hidden UIView objects to the view hierarchy to act as the yellow spaces. With iOS 9 you can replace these views with three layout guides. A UILayoutGuide has a layout frame (CGRect), layout anchors and an owning view but it is not part of the view hierarchy.
Note: Interface Builder does not support layout guides yet (Xcode 7.2.1). So if you want to use them you must create your constraints in code.
Setting up the Views and Layout Guides
To create this layout we first add the three layout guides and the two buttons as properties of the view controller. I will show each code snippet first in Swift and then in Objective-C:
let leadingGuide = UILayoutGuide()
let noButton = UIButton(type: .Custom)
let middleGuide = UILayoutGuide()
let yesButton = UIButton(type: .Custom)
let trailingGuide = UILayoutGuide()
The Objective-C version of this setup code is more verbose, we first need some properties for each view and guide:
I am going to skip some of the boilerplate code to configure the buttons. The code is all called from the viewDidLoad method of the view controller. See the example project for details. Once we have the buttons we add them as subviews to the top level view as normal:
Note that we do not use addSubview for the layout guides. Remember that layout guides are not part of the view hierarchy. A layout guide needs an owning view which you assign with the addLayoutGuide method.
With the views and layout guides created we can add our constraints. This is pretty much the same as if we were using spacing views. First we will set the leading and trailing constraints working from left to right. A layout guide has layout anchors just like a regular view that we use to set the constraints. If you need a recap on how to use layout anchors see my post on pain free constraints with layout anchors.
Layout Margin Guides
We are spacing the buttons relative to the margins of the superview so we will need the layout margins guide:
let margins = view.layoutMarginsGuide
UILayoutGuide *margins = self.view.layoutMarginsGuide;
Leading Layout Guide
The leading layout guide controls the space between the left margin and left button: