Programmaticaly add constraints to layout guides

Top layout guide
Top and Bottom Layout Guides.

They represent the upper and lower limit from where you can safely layout custom views or UIKit toolbar/search bar in your view controller, without worrying that the status bar, navigation bar, or tab bar will cover them under top and bottom extended layout edges. Using storyboard Xcode’s Interface Builder will automatically add them inside a view controller scene for easy pinning with view’s top or bottom edge constraints. But what if you don’t use storyboard?

View controller without storyboard.

There are many cases when you need to account for the top and bottom layout guides in building a view with interface builder outside storyboard. The most common case is when you are still instantiating a view controller with NIB/XIB as the view.

Programmatical approach.

Let’s see how to pin a simple UISearchBar in a view controller under the embedding navigation controller’s navigation bar. After you have completely laid out all the view and pinned all edges, select the constraint that pin the top of the search bar to top of the superview and tick the “Placeholder” checkbox to indicate that it must be removed at build time.

Placeholder constraint

You must do this because later we will programmatically add a constraint that pins the same top of the search bar to top layout guide. If Auto Layout engine while doing it’s magic find two constraints that pin the same edge to different places it will raise an exception saying “Unable to simultaneously satisfy constraints”.

While you are in Interface Builder create an outlet for the search bar, mine is called SrchBar_Header.

Now somewhere in viewDidLoad add this piece of code:

And that’s it, enjoy the automatically adjusted position of the search bar when rotating to landscape compact size class and back to normal!

How to get current UIBarMetrics value

Navigation signage

you can’t… or at least I can’t find a way to get UIBarMetrics¬†either from self.navigationBar¬†or from self.navigationItem. There is simply no public getter methods in all UINavigationBar related API’s!

What can we do?

By relying on UITraitCollection and getting horizontal and vertical size classes we can deduce if we are in a regular or a compact condition. App’s navigation bar enters in compact metrics when both horizontal and vertical size classes are compact.

This way we cover UIBarMetricsDefault and UIBarMetricsCompact, leaving to the further deduction UIBarMetricsDefaultPrompt and UIBarMetricsCompactPrompt. But at least it’s something!

If you also need to adapt dynamically when the iOS interface environment changes (e.g. when the device is rotated), then you need to listen to UIViewController conforming UITraitEnvironment protocol delegate callback traitCollectionDidChange: