June 9, 2021

Guide for UIKeyboardLayoutGuide

The article is now available on my blog:

A common task making app layout is keyboard avoidance. Since iOS 14.0 it works automatically for SwiftUI views. What’s about old, but good UIKit? Previously we used keyboard notifications, checked keyboard height, and updated related constraints. iOS 15 introduces a new layout guide — UIKeyboardLayoutGuide. It’s super intuitive if you’re familiar with other guides like safeAreaLayoutGuide and readableContentGuide. Let’s try to use it in a simple example — we have a login screen with text fields and a login button pinned to the bottom.

Base usage

We add just two constraints with system spacing:

let buttonBottom = view.keyboardLayoutGuide.topAnchor.constraint(equalToSystemSpacingBelow: loginButton.bottomAnchor, multiplier: 1.0)
let buttonTrailing = view.keyboardLayoutGuide.trailingAnchor.constraint(equalToSystemSpacingAfter: loginButton.trailingAnchor, multiplier: 1.0)
NSLayoutConstraint.activate([buttonBottom, buttonTrailing])

Now loginButton layout follows keyboard changes. When the keyboard is offscreen, keyboardLayoutGuide.topAnchor matches the view's safeAreaLayoutGuide.bottomAnchor.

Works as simple as it must be

That's all, thank you for coming to my TED talk! Wait, the keyboard is no so simple, especially on iPadOS. You can undock and drag it to any place. Luckily, the keyboard guide helps us to handle these cases.

It's easier to type with one hand

Working with floating keyboards

At first, we must enable keyboard tracking, it's disabled by default:

view.keyboardLayoutGuide.followsUndockedKeyboard = true

Now, loginButton starts to follow the keyboard:

Keyboard is the part of our apps too

It works great, but here we have edge cases. When we move the keyboard at the top, loginButton may be outside of the view frame.

Actually, UIKeyboardLayoutGuide is a subclass of UITrackingLayoutGuide. It's a layout guide that automatically activates and deactivates constraints depending on its nearness to edges. To use it, we replace buttonTrailing constraint with:

let buttonTop = view.keyboardLayoutGuide.topAnchor.constraint(equalToSystemSpacingBelow: loginButton.bottomAnchor, multiplier: 1.0)
buttonTop.identifier = "buttonTop"
view.keyboardLayoutGuide.setConstraints([buttonTop], activeWhenAwayFrom: .top)

buttonTop constraint will be active only when the keyboard is away from the top. Finally, we add buttonBottom constraint to pin loginButton at the keyboard bottom:

let buttonBottom = loginButton.topAnchor.constraint(equalToSystemSpacingBelow: view.keyboardLayoutGuide.bottomAnchor, multiplier: 1.0)
buttonBottom.identifier = "buttonBottom"
view.keyboardLayoutGuide.setConstraints([buttonBottom], activeWhenNearEdge: .top)
Note: configuring identifiers for NSLayoutConstraint allows you to find constraints easily during debugging.

Here is a final demo of our example. I've added some leading and trailing constraints as well. Check out UIKeyboardLayoutGuideExample on Github.

Related resources

Twitter · Telegram · Github