Introduction

Ryan Fox
6 min readApr 28, 2018

Note: topLayoutGuide and bottomLayoutGuide have been deprecated in iOS 11. It’s worth understanding them for dealing with iOS 10 code and to give yourself a nice starting place for learning about what changed in iOS 11.

In my last post I discussed what extended layout was in iOS and briefly touched on UIViewController’s topLayoutGuide. Because the post wasn’t centered around layout guides I didn’t go too far into it. It’s something worth knowing and a prerequisite (at least in my eyes) to understand the changes Apple made in iOS 11 to accommodate the iPhone X, so we’ll explore that today.

Note that I’ll be speaking about the topLayoutGuide and how it interacts with navigation bars and the status bar specifically; there is an equivalent bottomLayoutGuide which operates very similarly, just with toolbars and tab bars instead of status and navigation bars.

UIKit on “topLayoutGuide”

Unlike extended layout, Apple’s actually pretty clear when it comes to topLayoutGuide. Let’s work through what the UIKit documentation has for us (bolding mine) and stop for notes along the way.

The topLayoutGuide property comes into play when a view controller is frontmost onscreen. It indicates the highest vertical extent for content that you don't want to appear behind a translucent or transparent UIKit bar (such as a status or navigation bar). This property implements the UILayoutSupport protocol and you can employ it as a constraint item when using the NSLayoutConstraint class.

The topLayoutGuide conform to UILayoutSupport, a protocol introduced in iOS 7 along with the top and bottom guides. Apple goes on to explain how the topLayoutGuide actually behaves:

[The topLayoutGuide] is constrained by either the view controller or by its enclosing container view controller (such as a navigation or tab bar controller), as follows:

* A view controller not within a container view controller constrains this property to indicate the bottom of the status bar, if visible, or else to indicate the top edge of the view controller’s view.

Using a simple example of a UIViewController filling the screen inside of a UINavigationController, this would mean the navigation controller constrains its topLayoutGuide’s bottom to just below the status bar (when visible) or to the top of its view. The view itself will go underneath the status bar, but the topLayoutGuide bottom will lie below it (when visible). The next part of the documentation goes on to explain how the contained view controller’s topLayoutGuide behaves:

* A view controller within a container view controller does not set this property’s value. Instead, the container view controller constrains the value to indicate:

** The bottom of the navigation bar, if a navigation bar is visible

** The bottom of the status bar, if only a status bar is visible

** The top edge of the view controller’€™s view, if neither a status bar nor navigation bar is visible

If a container navigation controller’€™s navigation bar is visible and opaque, the navigation controller lays out the frontmost view controller’€™s view so its top edge abuts the bottom of the navigation bar.

Essentially, if our view controller is inside of a container view controller, the container will adjust our topLayoutGuide according to the above rules, and all of the above rules basically amount to “the container will set the contained view controller’s topLayoutGuide’s bottom to where the visible content starts”. It’s an important distinction that it’s not set to where the view itself starts, but where the visible content starts. This all loops back into how extended layouts work in iOS.

Visualizing the topLayoutGuide

That’s really all there is to it. Let’s look now at what this all comes together to look like. For all of these examples, I’m going to keep the default edgesForExtendedLayout property of [.all] to introduce additional variables. This means our views will extend underneath translucent bars. Everything you see below is just a bunch of buttons within a UIStackView on UIViewController’s default self.view. The stack view constrains its centerYAnchor with self.view’s centerYAnchor.

The navigation controller’s topLayoutGuide will be in red and its view’s topAnchor will be in orange. The contained view controller’s topLayoutGuide will be in yellow and its view’s topAnchor will be in cyan. I’ve dimmed the navigation bar so we can see behind it. Let’s look at the three relevant combinations of showing/hiding a navigation bar and having it translucent or not when visible:

When we have a translucent navigation bar, our contained view is pinned to the top of our navigation controller’s view. The navigation controller’s view is pinned to the top of the screen, but its topLayoutGuide’s bottom is pinned beneath the status bar. In effect, this means that a navigation controller’s view, just like any other, will extend behind the bar above it (the status bar in this case) but its visible content, such as the “Navigation Bar” text, is constrained to its topLayoutGuide’s bottom.

What about when the navigation bar is opaque/non-translucent? The navigation controller’s topLayoutGuide hasn’t changed as we haven’t affected the bar above it. If the status bar were removed, we’d see the topLayoutGuide move to the top of the screen (it would have a length of zero). The contained view controller’s topLayoutGuide hasn’t moved, either. This makes sense; translucent or not, the “visible content” still starts beneath the navigation bar. All that changed is the contained view’s topAnchor. We no longer have a status bar to extend underneath, so the view’s topAnchor and the topLayoutGuide are equivalent.

Finally, when we have no navigation bar, the two notable changes with the contained view are the view’s topAnchor moving to the top of the screen, sharing it with the navigation controller’s view, and its topLayoutGuide doing the same. All the view has to extend behind is the status bar now, but its visible content should still begin below the status bar.

You can apply any of the rules in the previous post on extended layouts and see the behavior you expect.

In Summary

  • A UIViewController’s topLayoutGuide is set by Apple to determine where the visible content should start laying out
  • For container view controllers like UINavigationController, the topLayoutGuide’s bottom is set to the bottom of the status bar if visible or to the top of the view controller’s view if the status bar is not visible
  • For view controllers within container view controllers, the topLayoutGuide is set by the container to end below the status bar, the navigation bar, or both, depending on which are visible
  • A difference in a a view controller’s topLayoutGuide and its topAnchor implies an extended layout, where the view extends above the visible content/topLayoutGuide
  • bottomLayoutGuides behave the same, but respect tab bars/toolbars instead of navigation bars and the status bar

With all of the above and extended layout knowledge now under your belt, you should be able to jump into this fantastic write-up on Apple’s safe area changes in iOS 11 and understand how old properties were transitioned into the newer ones.

Feel free to reach out to me on Twitter @Wailord if you’ve any feedback or questions!

--

--

Ryan Fox

iOS developer @Facebook — the opinions expressed here are mine and do not necessarily represent those of my employer. https://www.linkedin.com/in/wailord