A quick guide to laying out views in iOS
How to prevent tab bars and navigation bars getting in your way.
Recently, like many of you, we’ve been tackling some compatibility issues with the iPhone X. A lot of these boiled down to not using the APIs Apple gave us a few years ago, in order to make this easier, and not everyone was familiar with these, or how to use them.
So here’s a really quick guide!
Layout guides keep views from going underneath bars
View Controllers have two layout guides — the topLayoutGuide
and the bottomLayoutGuide
(yes, these were deprecated in iOS 11. You can read more about that nearer the bottom of this post).
They’re very useful — in the case your view controller is in a UINavigationController
, the .bottomAnchor
property of the topLayoutGuide
corresponds to the bottom of the navigation bar. In the case that it isn’t, this bottom anchor is simply the top of the view controller.
What this means is that if you want a view to be pinned below the navigation bar, you should use something like this:
label.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
If you constrain this to the view controller’s .view.topAnchor
instead, you risk your view being underneath the navigation bar — probably not what you want. Also note that the top of the label is constrained to the bottom of the layout guide — a really frequent mistake is to do this the wrong way round!
Likewise, to avoid items going underneath the the tab bar, constrain items to the bottomLayout.topAnchor
, instead of the view.bottomAnchor
. Even if your views aren’t in a tab bar controller or navigation bar controller, its a good idea to use these anchors, in case that you change this in the future.
If you see any constraints to a view controller’s view’s top or bottom, you’re going to want to change them:
label.topAnchor.constraint(equalTo: view.topAnchor).isActive = true // change me!!!
⚠️ A really annoying thing is that these layout guides are not available in XIBs, nor is it possible to initalise NSLayoutConstraint
to use a layout guide. They just don’t exist. If you want to use them (and you do!), you have to do them in code as above, or use storyboards. This is improved with the safeAreaLayoutGuide
, which we talk about below.
Here’s a good overview of the layout guides:
Use edgesForExtendedLayout if you are a rebel
A view controller also has a property edgesForExtendedLayout
, that you can use. This indicates which edges of a view can go under chrome provided by a parent view controller (e.g. the nav bar or tab bar). You can simply turn this off using edgesForExtendedLayout = []
. However, then you don’t get the nice behaviour that the content slides under the semi-transparent navigation bar, and it can look weird.
Use at your peril.
Safe areas make your app fully iPhone X-proof
safeAreaLayoutGuide
is the new and shiny API intended to replace topLayoutGuide
and bottomLayoutGuide
. Confusingly, a safe area layout guide is on a view and not a view controller, like topLayoutGuide
was. If you’re using a XIB or storyboard, you can choose to use this by checking “Safe Area Layout Guides” in the File Inspector.
In most cases, the topAnchor
of the safeAreaLayoutGuide
is equivalent to the bottomAnchor
of the old topLayoutGuide
. Confused? You’re not alone. 😁
Essentially, top/bottomLayoutGuide
defines the areas you shouldn’t put stuff, where as safeAreaLayoutGuide
defines the areas you should put stuff.
As safe areas are on views, this means that you can use them in XIBs, which is great. You still can’t use them using the NSLayoutConstraint initialiser, however. Safe areas also have the benefit of making the iPhone X in landscape look OK using the leadingAnchor
and trailingAnchor
— else you risk your app have the notch “cut out” of your UI.
Conclusion
Take these things into account if you want your app to work for iPhone X:
- Definitely don’t constrain to a view controller’s view’s top or bottom
- Don’t fiddle with
edgesForExtendedLayout
unless you absolutely must - Do constrain to the
topLayoutGuide.bottomAnchor
orbottomLayoutGuide.topAnchor
- OR do constrain to the
safeAreaLayoutGuide
, if you want your app to look great on an iPhone X in landscape.
Enjoy your notches!