Guide for UIKeyboardLayoutGuide
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:
view.addSubview(loginButton)
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
.
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.
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:
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.
I've added some leading and trailing constraints as well. Check out UIKeyboardLayoutGuideExample on Github.