Exploring Visual Format Language with Swift
A couple weeks ago I got introduced to the idea of how to use Auto Layout in Objective-C and Swift to make sure that my app appears correctly across all iOS devices. You can create constraints in Interface Builder(IB) or build them programmatically. Having a background in visual design, I instantly gravitated towards IB because it reminds me of many design programs. The reality seems to be that often times building programmatic constraints tends to be more reusable and readable by other people that may be working with your project. So I was curious to find out if there was a way to structure programmatic constraints a bit more visually. Enter constraints with the Visual Format Language.
Visual Format Language
Visual Format Language allows you to build programmatic constraints using visual syntax strings. The idea is the text visually matches the layout. Here is an excerpt Apples Documentation:
A Complete Line of Layout
H:|-[find]-[findNext]-[findField(>=20)]-|

Let’s break that down:
H: (Horizontal) //horizontal direction
| (pipe) //superview
- (dash) //standard spacing (generally 8 points)
[] (brackets) //name of the object (uilabel, unbutton, uiview, etc.)
() (parentheses) //size of the object
So if we were to say that in a sentence, we would say the findButton is 8 points of padding (white space) from the superview’s leading (left edge) and 8 points of padding from the findNextButton’s leading. The findNextButton is 8 points of padding from the findField’s leading. Finally the findField size is at least 20 points and it has 8 points of padding from the superview’s trailing (right edge).
What is particularly interesting about the code above is that it handles (sets) all of the horizontal constraints need for the findButton, findNextButton, and findField at the same time.
There is a lot of magic that is happening here so I’m going to do my best to walk you through a basic example of how you would implement this in a mock project.
In a swift project we need to add some objects to your superview that we can attach constraints too. I also favor adding a background color to your object so you can see the space it takes up when testing out your constraints:
override func viewDidLoad() {super.viewDidLoad()
//create four view objects to represent elements in our superview
let topBar = UIView()
let middleFrameTop = UIView()
let middleFrameBottom = UIView()
let bottomBar = UIView()
//set the background color of those subviews
topBar.backgroundColor = UIColor.grayColor()
middleFrameTop.backgroundColor = UIColor.orangeColor()
middleFrameBottom.backgroundColor = UIColor.blueColor()
bottomBar.backgroundColor = UIColor.grayColor()
//add the subviews to the superview
self.view.addSubview(topBar)
self.view.addSubview(middleFrameTop)
self.view.addSubview(middleFrameBottom)
self.view.addSubview(bottomBar)
//remove any constraints we may have made in Interface Builder
topBar.translatesAutoresizingMaskIntoConstraints = false
middleFrameTop .translatesAutoresizingMaskIntoConstraints = false
middleFrameBottom.translatesAutoresizingMaskIntoConstraints = false
bottomBar.translatesAutoresizingMaskIntoConstraints = false
}
Now that we have the basic setup, we can start working on our constraints with the Visual Format Language. The first piece we need to add is creating a dictionary that holds our subviews with reference keys. We will also create an array to hold our constraints. Add it to your viewDidLoad function for now.
let viewsDict = [“topBar”: topBar, “middleFrameTop”: middleFrameTop , “middleFrameBottom”: middleFrameBottom, “bottomBar”: bottomBar];
var viewConstraints = [NSLayoutConstraint]()
Here we are setting the reference string that we will refer to when making constraints with Visual Format Language. Now we can start building our horizontal constraints:
let topBarConstraintsHorizontal = NSLayoutConstraint.constraintsWithVisualFormat(
“H:|-16-[topBar]-16-|”,
options: [], metrics: nil, views: viewsDict)
viewConstraints += topBarConstraintsHorizontal
//Creates horizontal constraints with 16 points of padding from the superview’s leading and trailing edges
//Notice we reference our viewsDict
//Add our constraints to the constraints array
let middleFrameTopHorizontal = NSLayoutConstraint.constraintsWithVisualFormat(
“H:|-16-[middleFrameTop]-16-|”,
options: [], metrics: nil, views: viewsDict)
viewConstraints += middleFrameTopHorizontal
//Creates horizontal constraints with 16points of padding from the superview’s leading and trailing edges
let middleFrameTopBottomHorizontal = NSLayoutConstraint.constraintsWithVisualFormat(
“H:|-16-[middleFrameTopBottom]-16-|”,
options: [], metrics: nil, views: viewsDict)
viewConstraints += middleFrameBottomHorizontal
let bottomBarHorizontal = NSLayoutConstraint.constraintsWithVisualFormat(
“H:|-16-[bottomBar]-16-|”,
options: [], metrics: nil, views: viewsDict)
viewConstraints += bottomBarHorizontal
The next step is to build our vertical constraints:
let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
"V:|-40-[topBar]-16-[middleFrameTop(==topBar)]-16-[middleFrameBottom(==topBar)]-16-[bottomBar(==topBar)]-20-|",
options: [], metrics: nil, views: viewsDict)
viewConstraints += verticalConstraints
//creates vertical constraints where topBar is 40 points of padding from the superview's top edge and 16 points of padding from middleFrameTop's top.
//middleFrameTop's size is equal to topBar's side and 16 points of padding from middleFrameBottom.
//middleFrameBottom and bottomBar are also equal to topBar's size and they are 16 points of padding from each other.
//bottomBar is 20 points of padding from superview's bottom edge.
At this point we have create all the auto layout constraints that we need. We can attach our constraints from our constraints array with:
NSLayoutConstraint.activateConstraints(viewConstraints)
When we run the application it looks like this:

If we wanted to get a bit more fancy we could change our vertical constraints to look something like this:
let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat(
"V:|-40-[topBar(>=20,<=50)]-16-[middleFrameTop]-16-[middleFrameBottom(==middleFrameTop)]-16-[bottomBar(==topBar)]-20-|",
options: [], metrics: standardMetrics, views: viewsDict)
viewConstraints += verticalConstraints
//we are setting the topBar's size to have a height of at least 20 points but no more than 50 points (>=20,<=50)
//we make the bottomBar's size equal to the topBar's size.
//we can make the middleFrames equal to each other by setting middleBottomFrame to equal the size of middleTopFrame (==middleFrameTop)
///because the topBar and bottomBar know their size and location in reference to the superview, it will automatically calculate the size of middleTopFrame and middleBottomFrame.
//this means that middleTopFrame and middleBottomFrame will each take up half of the available remaining space

Here is the full code in one piece:
override func viewDidLoad() {super.viewDidLoad()
//create subviews
let topBar = UIView()
let middleFrameTop = UIView()
let middleFrameBottom = UIView()
let bottomBar = UIView()
//set background colors of the views
topBar.backgroundColor = UIColor.grayColor()
middleFrameTop.backgroundColor = UIColor.orangeColor()
middleFrameBottom.backgroundColor = UIColor.blueColor()
bottomBar.backgroundColor = UIColor.grayColor()
//add subviews to superview
self.view.addSubview(topBar)
self.view.addSubview(middleFrameTop)
self.view.addSubview(middleFrameBottom)
self.view.addSubview(bottomBar)
//remove any constraints in interface builder
topBar.translatesAutoresizingMaskIntoConstraints = false
middleFrameTop .translatesAutoresizingMaskIntoConstraints = false
middleFrameBottom.translatesAutoresizingMaskIntoConstraints = false
bottomBar.translatesAutoresizingMaskIntoConstraints = false
//build dinctionary of views
let viewsDict = ["topBar": topBar,
"middleFrameTop": middleFrameTop ,
"middleFrameBottom": middleFrameBottom,
"bottomBar": bottomBar];
//build array to store constraints
var viewConstraints = [NSLayoutConstraint]()
//creates vertical constraints
let verticalConstraints = NSLayoutConstraint.constraintsWithVisualFormat("V:|-40-[topBar(>=20,<=50)]-16-[middleFrameTop]-16-[middleFrameBottom(==middleFrameTop)]-16-[bottomBar(==topBar)]-20-|", options: [], metrics: nil, views: viewsDict)
viewConstraints += verticalConstraints
//creates horizontal constraints
let topBarConstraintsHorizontal = NSLayoutConstraint.constraintsWithVisualFormat("H:|-16-[topBar]-16-|", options: [], metrics: nil, views: viewsDict)
viewConstraints += topBarConstraintsHorizontal
let middleFrameTopHorizontal = NSLayoutConstraint.constraintsWithVisualFormat("H:|-16-[middleFrameTop]-16-|", options: [], metrics: nil, views: viewsDict)
viewConstraints += middleFrameTopHorizontallet middleFrameBottomHorizontal = NSLayoutConstraint.constraintsWithVisualFormat("H:|-16-[middleFrameBottom]-16-|", options: [], metrics: nil, views: viewsDict)
viewConstraints += middleFrameBottomHorizontallet bottomBarHorizontal = NSLayoutConstraint.constraintsWithVisualFormat("H:|-16-[bottomBar]-16-|", options: [], metrics: nil, views: viewsDict)
viewConstraints += bottomBarHorizontal//active all constraints
NSLayoutConstraint.activateConstraints(viewConstraints)
}
There are a lot of other extra pieces to Visual Format Language but for now I will let that digest a bit. While it may seem confusing at first, I think it simplifies programmatic constraints with a bit of practice. It definitely is more readable on first glance. Until next time, I hope this helps to introduce you to using Visual Format Language constraints.