Keyboard Management

James Pang
Tech with Pangers
Published in
4 min readDec 28, 2016

Quite often in iOS, we will need to build screens that contain one or more text fields in which the user can input some values. In these situations, it is not unusual to have some of your screen elements blocked by the keyboard that pops up on screen. In fact, this happens all too often, so let’s explore how we can find a reusable solution to this problem.

So to restate the problem more specifically, I wanted to be able to make UIViewController’s `aware` of the keyboard in a reusable fashion. Perhaps I could make a protocol called `KeyboardAvoidable` that UIViewControllers could conform to so they can receive this behaviour. So thats exactly what I did.

Any object that conforms to this protocol will have a `keyboardOpen` boolean which, as the name suggests, tells us whether the keyboard is open or not.

Now since we want this behaviour to be reusable, lets create a protocol extension that implements some behaviour so that any object that conforms to `KeyboardAvoidable` will receive the behaviour automatically. Furthermore, lets constraint the protocol extension to UIViewControllers. What this will do is allow us to gain access to important properties on UIViewControllers such as `self.view` from within the protocol extension.

In the protocol extension, the function `setupKeyboardNotifications` is implemented which listens to the `NotificationCenter` for the `willShow` and `willHide` events of the keyboard. Note the `setupKeyboardNotifications` function is not defined in the protocol. The reason for this is that any implementation of `setupKeyboardNotifications` will essentially be the same (listening for the specific keyboard events) and hence we can just provide default implementations that the conforming object will just receive for free. Secondly, we opted to go for the `addObserver` method that uses a closure rather than a selector as the protocol extension does not have the objective-C run time available to it (which is required to use selectors). Unfortunately, this means we also have to create a function called `removeKeyboardNotifications` that deregisters the conforming object from any new notifications. Next lets implement `keyboardWillAppear` and `keyboardWillDisappear`.

This is quite a bit of code so lets break this down. In the `keyboardWillAppear` method:

  1. We pass the notification into a `KeyboardNotification` object. This object is inspired by this gist and deals with parsing certain properties from the notification which we can use (I will show you my implementation of `KeyboardNotification` at the end). We pull out the duration of the animation, animation curve and the keyboard’s frame when it is fully open.
  2. We check if the keyboard is not open and if the keyboard height does not change between the start and end frame of its animation. In this case, that means the keyboard is appearing from a disappeared state and so we adjust the height of `self.view` accordingly and animate it with the curve and duration that we extracted before.
  3. However if the keyboard is already open, but the keyboard height changes between the start and end frame of its animation, that means something about the keyboard has changed. So we adjust the height of `self.view` accordingly and animate the changes.

In the `keyboardWillDisappear` method:

  1. Once again we pass the notification in `KeyboardNotification` and pull out some values that will be handy for us.
  2. We check if the keyboard is open, in which case, we adjust the height of `self.view` and animate the changes.

Finally, we can move onto implement this protocol on a UIViewController!

As you can see, all we have to do is call `setupKeyboardNotifications` in `viewDidLoad` and `removeKeyboardNotifications` in `deinit`. Now our UIViewController’s height will automatically adjust (in an animated fashion) in reaction to keyboard events. Of course, you would need to add a UITextField to the view hierarchy to trigger the keyboard to show up, but you get the point. Also typically a UIScrollView would be used so that as the keyboard is show, all the elements on screen we be visible by scrolling to them, even if they are beyond the height of the view. However I will leave that for another time.

What I like about this approach is that we are adding behaviour to the UIViewController via composition (using protocols) as opposed to inheritance (using a superclass). This makes it easy for the developer to make changes to the protocol, while having a degree on confidence that something didn’t break due to the flat hierarchy that protocols offer (great read here for more info). However, the downside is that we have a write an extra few more lines to register and deregister for the keyboard notifications each times we want to use this protocol on a new UIViewController (With a superclass we won’t have to do that).

Here is a fully working project that I made using this approach for keyboard management taken a step further. It contains the `KeyboardNotification` class that I referenced earlier in the post if you would like to see how it is implemented. Feel free to run the project, take a look at the code and ask me any question if you have any.

--

--