Daily coverage of WWDC21.
A Swift by Sundell spin-off.

Integrating the virtual keyboard into your app with the keyboard layout guide

Published at 14:40 GMT, 10 Jun 2021
Written by: Gui Rambo

One of the most annoying things that iOS developers have had to deal with over the years has been avoiding the keyboard, making sure that it won’t cover our app’s UI so that the user can see what they’re doing while they’re typing on the virtual keyboard.

Notice how I — and developers in general — use the term “avoid” when talking about the keyboard, as if the keyboard is something bad that we have to avoid within our apps. Well, this year Apple is introducing new APIs that make this task so easy that they want developers to look at the keyboard as their friend, and not as an enemy that should be avoided.

Every UIView on iOS now has a new keyboardLayoutGuide property. This layout guide enables us to use auto layout constraints to attach our own views to the keyboard in several ways. Not only that, but UIKeyboardLayoutGuide inherits from UITrackingLayoutGuide, a new type of layout guide that can activate and deactivate constraints automatically based on the guide’s proximity to certain screen edges.

Attaching a view to the keyboard

Let’s build a very simple example to demonstrate how this new keyboard layout guide works. In a blank UIKit-based project, let’s add a simple text field with a background to our view controller’s view:

class ViewController: UIViewController {
    private lazy var textField: UITextField = {
        let field = UITextField()
        
        field.translatesAutoresizingMaskIntoConstraints = false
        field.borderStyle = .roundedRect
        
        return field
    }()
    
    private lazy var backgroundView: UIVisualEffectView = {
        let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial))
        
        effectView.layer.cornerRadius = 8
        effectView.layer.cornerCurve = .continuous
        effectView.translatesAutoresizingMaskIntoConstraints = false
        effectView.clipsToBounds = true
        
        return effectView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
                
        view.addSubview(backgroundView)
        backgroundView.contentView.addSubview(textField)

        // Make the text field fill the background view, with some padding.
        NSLayoutConstraint.activate([
            textField.leadingAnchor.constraint(equalTo: backgroundView.contentView.leadingAnchor, constant: 8),
            textField.trailingAnchor.constraint(equalTo: backgroundView.contentView.trailingAnchor, constant: -8),
            textField.topAnchor.constraint(equalTo: backgroundView.contentView.topAnchor, constant: 8),
            textField.bottomAnchor.constraint(equalTo: backgroundView.contentView.bottomAnchor, constant: -8),
        ])

        // Make the background view fill the screen horizontally, with some padding.
        NSLayoutConstraint.activate([
            backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8),
            backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -8),
        ])
    }
}

The above is all fairly straightforward, but we haven’t yet added any vertical positioning constraints to our backgroundView. What I would like to achieve is for the background view to always be attached to the bottom of the screen, and to float up with the virtual keyboard when it shows up. With the new keyboard layout guide, this can be done quite simply:

NSLayoutConstraint.activate([
    view.keyboardLayoutGuide.topAnchor.constraint(
        equalTo: backgroundView.bottomAnchor,
        constant: 8
    )
])

Here we’re telling auto layout that our view’s bottom edge should always be at the top of the keyboard, with an additional padding of 8 points. When the keyboard disappears, the top of the keyboard layout guide will correspond with the bottom of the safe area layout guide, so the behavior is exactly what we would expect it to be:

The keyboard on iPhone with a floating text field that follows it

Notice how the layout guide will even follow the animations that occur when the keyboard is presented and dismissed, and we were able to do all of this with very little code, thanks to the new keyboard layout guide.

Handling the floating keyboard on iPad

The above example works really well on iPhone. However, the iPad has a more complicated keyboard, because it can be undocked and moved around the screen quite freely, which can be a bit challenging in terms of layout.

If you run the example as-is on iPad and enable the floating keyboard, you’ll notice that the text field simply falls back to the bottom of the screen, and doesn’t follow the keyboard. So, if we want our keyboard layout to also follow the floating keyboard on iPad, then we need to enable that explicitly:

view.keyboardLayoutGuide.followsUndockedKeyboard = true

With that enabled, our text field will then follow the floating keyboard as expected. This is far from perfect, though, as our view will keep filling the entire width of the screen, even though the keyboard is now a lot smaller than before. Depending on your app, this might be what you want, but in my example I’d like the text field to more or less follow the width of the keyboard:

NSLayoutConstraint.activate([
    backgroundView.leadingAnchor.constraint(
        equalTo: view.keyboardLayoutGuide.leadingAnchor,
        constant: 8
    ),
    backgroundView.trailingAnchor.constraint(
        equalTo: view.keyboardLayoutGuide.trailingAnchor,
        constant: -8
    ),
    backgroundView.widthAnchor.constraint(
        greaterThanOrEqualToConstant: 180
    )
])

Now our view follows the width of the keyboard. However, there are situations when the keyboard might be too small for our text field, which is why I used a greaterThanOrEqualToConstant constraint for the view’s width.

The view on iPad, following the floating keyboard around the screen

If you drag the keyboard all the way to the top of the screen, you’ll notice an issue: our view disappears because it goes beyond the bounds of the screen at the top edge. That’s where a feature of UITrackingLayoutGuide, which the keyboard layout guide inherits from, comes in handy:

let topAttachment = view.keyboardLayoutGuide.topAnchor.constraint(
    equalTo: backgroundView.bottomAnchor,
    constant: 8
)

view.keyboardLayoutGuide.setConstraints([
    topAttachment
], activeWhenAwayFrom: .top)

let bottomAttachment = view.keyboardLayoutGuide.bottomAnchor.constraint(
    equalTo: backgroundView.topAnchor,
    constant: 8
)
bottomAttachment.priority = .defaultLow

view.keyboardLayoutGuide.setConstraints([
    bottomAttachment
], activeWhenAwayFrom: .bottom)

Instead of activating the constraint that attaches our view to the top of the keyboard directly, I’m telling the keyboard layout guide to activate that constraint only when the keyboard is away from the top of the screen. Then I have another constraint, this one attaching my view to the bottom of the keyboard, which I’m telling the keyboard layout guide to activate only when the keyboard is away from the bottom of the screen. I gave this constraint a lower priority in order to prevent conflicts from emerging while the keyboard is moving.

Now, whenever the user moves the keyboard towards the top of the screen, our text field gracefully moves to the bottom of the keyboard instead, and vice-versa:

The view on iPad, following the floating keyboard around the screen and moving to the bottom when the keyboard is at the top

Conclusion

Making our iOS layouts adapt to the virtual keyboard is now easier than ever, thanks to the new keyboard layout guide. There are a few additional things that you have to take into account when it comes to the floating keyboard on iPad, such as when your app is running in split screen with another app, so if you’d like to learn more details about that, then I highly recommend checking out session 10259 from WWDC21.

Written by: Gui Rambo
RaycastRaycast

Take the macOS Spotlight experience to the next level: Create Jira issues, manage GitHub pull requests and control other tools with a few keystrokes. Automate every-day tasks with scripts and boost your developer productivity by downloading Raycast for free.