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
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.
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])
loginButton layout follows keyboard changes. When the keyboard is offscreen,
keyboardLayoutGuide.topAnchor matches the view's
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
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.
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.
- Use the floating keyboard on your iPad by Apple
- Your guide to keyboard layout by Apple
- Adjust Your Layout with Keyboard Layout Guide by Apple
- SwiftUI keyboard avoidance by Federico Zanetello