How to handle keyboard behavior in iOS apps

Make on-screen keyboard and application UI friends

Mateusz Kuźnik
AzimoLabs
Published in
5 min readMay 25, 2021

--

In the mobile world, the on-screen keyboard is an inseparable part of almost all apps. We should never ignore how impactful it can be on user experience. In the end, it takes nearly half of the screen. With its dynamic size, sometimes changing on the fly, it can make your UI clunky and bring many frustrations to your customers.

This article will walk you through some of our experiences in making the Azimo iOS app layout working smoothly with the on-screen keyboard.

In the beginning, let’s take a look at the API provided by Apple in the UIKit. We can register observers to the NotificationCenter, which will notify us when the keyboard frame change:

All of those notifications come with a set of helpful information required to layout our UI correctly. We can find them in the userInfo property:

The UIKeyboardBoundsUserInfoKey is deprecated, and you should not use it!

The most common solution to handle keyboard appearance is registering for UIResponder.keyboardWillShowNotification and UIResponder.keyboardWillHideNotification notifications in a ViewController instance. And then update the layout for each invocation by updating the insets of the scroll view.

This approach is good if you have only one place in the app with user input fields. When you have more places like this, you need to copy-paste the code and adjust it.

To avoid creating boilerplate, we can rely on another UIKit solution — Safe Area.

Safe Area presentation form UIKit documentation (link)

Safe Area is a layout guide that represents available space for your app’s content. To use it, you can connect your views to it and rely on AutoLayout to handle all changes for you. Safe Area takes into account things like navigation bars, so you are sure that they never overlap your content.

Why not make Safe Area aware of keyboard size then, so the AutoLayout engine handles its appearance for us?

Sadly it’s not possible to create a code like this:

It’s because UIView.safeAreaInsets property is read-only.

Fortunately, we can adjust the view controller’s safe area by modifying the UIViewController.additionalSafeAreaInsets property.

KeyboardAppearListener, our remedy

Let’s build an elegant and reusable solution step by step.
Firstly, we will create an object that holds our logic to reuse it in multiple places.

The first two properties are helper objects to handle the notification logic. I recommend you to check out this article from Ole Begeman for more.

For now, the code is obvious. We register for the UIResponder.keyboardWillShowNotification and UIResponder.keyboardWillHideNotification notifications which call our internal functions.

Now, let’s implement our keyboardWillShow function. In the beginning, we need to set up a guard to make sure that all required data is available:

We need to get the beginning and the end frame and compare these values. This check is not required, but there is no point in performing the rest of the logic if nothing changed. And this can happen many times as the system posts a notification each time the user taps on the text field (even the same).

Next, we calculate the new safe area insets for the keyboard.

It could sound reasonable to use the keyboard height, but the system calls our logic for each frame change. For example, when you switch from the default text field to the email field, the system may add a view with email addresses to select. For that reason, we use the difference between the Y value.

We need to remember that the system attaches the keyboard to the screen’s bottom edge, and we are calculating the additional safe area. It means that the computed bottom inset is too big. To fix this, we need to subtract the “window” safe area bottom inset. We do not have access to this value directly, but we can easily calculate it. And of course, we want to do it only once, so we need to add a new variable windowsSafeAreaWereAdded to our class.

The final version is:

In the end, to be a good citizen, we should animate our changes along with the keyboard’s appearance animation.

The body of the keyboardWillHide function is almost identical. The difference is in the math we use to calculate the additional safe area insets.

We are almost there. The code works well as long as we do not rotate the device while the keyboard is on the screen. In that case, our math does not work anymore. Why? It’s because of how the iOS informs us about the change. The flow is:

  1. the user rotates the device
  2. the system performs rotations
  3. the system pushes the UIResponder.keyboardWillHideNotification notification,
  4. the system pushes the UIResponder.keyboardWillShowNotification notifications.

The order of those steps is the key here. After a rotation, the bottom size of the safe area is different. If you remember, we calculate the safe area each time we need to use it. This causes that after rotation (when the keyboard will hide is performed), we use a different value for the windowSafeArea than was used to calculate the additional safe area. To fix that, we need to store the previously used value in the local variable and use it instead of calculating it.

Now, all you need to do is create the instance of the KeyboardAppearListener and store it as long as your view controller is alive.

On this animation, you can see the sticky button. If you are interested in how to implement it with a similar approach, stay tuned 😉.

Here is the final implementation of our KeyboardAppearListener. We do not create a separate framework for it as the class has less than 90 lines.

P.S. If you do not like the fact that we have to change the state by modifying the windowSafeArea and windowsSafeAreaWereAdded you are not alone. I’m not too fond of it as well. If you have an idea how to get rid of it, drop us a message!

Towards financial services available to all

We’re working throughout the company to create faster, cheaper, and more available financial services all over the world, and here are some of the techniques that we’re utilizing. There’s still a long way ahead of us, and if you’d like to be part of that journey, check out our careers page.

--

--