Topics

#99: Auto Layout Visual Format Language 🔤📐

Topics

In Bite #98, we learned how to work with Auto Layout in code. While this helped us gain a ton of flexibility, our code is now a bit... verbose. For simple layouts this won't be a big deal, but for anything complex we would quickly rack of hundreds of lines of code for just our layout. Today we'll look at one solution for this issue: Auto Layout's Visual Format Language. Let's take a look.

Before jumping into code, let's look at the Visual Format Language itself. It's essentially just a string that the system parses and turns into an array of NSLayoutConstraint objects:

"|-[header]-|"

The two pipes on the outside represent the superview. The dashes represent spacing, in this case, the system-standard spacing. Views are described with a name in brackets.

When parsed, this would create 2 new constraints: 1 leading and 1 trailing. It would keep the header the standard spacing away from the left and right edges of the superview. To let the system know our views by name we put them in a dictionary:

let views = [ "header": header ]

If we wanted to use a specific spacing amount we could describe that within dashes on the edges of our Visual Format Language:

"|-20-[header]-20-|"

That's fine for simple spacing, but what if we needed to reference lots of numeric values? We can name those and put them in a dictionary just like our views:

"|-edgeSpacing-[header]-edgeSpacing-|"

Now that we have a basic understanding, we can add our first set of constraints:

container.addConstraints(
  NSLayoutConstraint.constraintsWithVisualFormat(
    "|-[header]-|",
    options: NSLayoutFormatOptions(rawValue: 0),
    metrics: nil,
    views: [ "header": header ]
  )
)

We can prepend a H: or V: to describe constraints along the horizontal or vertical axes. If we don't prepend either, horizontal is assumed.

We can use parenthesis to describe a view's width or height:

"V:|[header(180)]"

Let's add 2 more constraints to pin our header to the top, and give it a fixed height:

container.addConstraints(
  NSLayoutConstraint.constraintsWithVisualFormat(
    "V:|[header(headerHeight)]",
    options: NSLayoutFormatOptions(rawValue: 0),
    metrics: [ "headerHeight": 180.0 ],
    views: [ "header": header ]
  )
)

We've only scratched the surface of what's possible with Visual Format Language. In the future we'll look at configuring inequalities, constraint priorities, and more.