Showing the iOS keyboard without a text input

Typically when the keyboard is shown in iOS it is in response to a user tapping on a UITextField  or UITextView .  Recently I wanted to display the keyboard in response to a user tapping a different type of control.  Today I will show you how I created a UIControl  subclass which can be used to display the keyboard.

func canBecomeFirstResponder() -> Bool

My first thought was that if we override canBecomeFirstResponder()  and return true  then we will be able to call becomeFirstResponder()  on our class and the keyboard will appear:

What we have now is a viewController which contains a FirstResponderControl .  We tell the control to become the first responder when tapped.  Let’s try it!

So now we run the app and tap the control.  Nothing happens.  Huh…  If we set a breakpoint inside FirstResponderControl ‘s canBecomeFirstResponder()  method we can see that that is called.  We’re on the right track.

UIKeyInput  (docs)

A subclass of UIResponder can adopt this protocol to implement simple text entry. When instances of this subclass are the first responder, the system keyboard is displayed.

In order to receive key input we must implement the UIKeyInput  protocol.  The protocol consists of three methods. func insertText(String) , func deleteBackward()  and  func hasText() -> Bool.  We will implement these methods by passing them on to a delegate:

And lets implement the delegate methods in our view controller:

And now if we build and run we have what we set out to.  A keyboard which affects the UI without the use of either UITextField  or UITextView .  This was a useful exercise but it’s unlikely that we’d ever implement something this way.  We could achieve everything above using a UIButton  and UITextView / UITextField .  So why?

The use case which led me down this interesting road was the following:  A view which when tapped presents a UIPickerView .  eg.

Screen Shot 2016-07-29 at 21.48.24Screen Shot 2016-07-29 at 21.49.16

inputView

Annoyingly if we try to set the inputView  property of our new class we get the error Cannot assign to property: 'inputView' is a get-only property .  This is because UIResponder  (one of UIControl’s parent classes) defines it as public var inputView: UIView? { get }  which makes it read only.  Fortunately we can overcome this by adding an inputView  property to our class:

For our example we’ll use a UIDatePicker  to update a label:

And that’s it!  You’ll notice that for the date picker example we don’t use the delegate at all.  This is because UIKeyInput  makes no sense as we aren’t receiving input from a keyboard.  Fortunately UIKit  is prepared for this circumstance and the UIKeyInput  protocol’s parent is perfect for just that.

UITextInputTraits (docs)

The UITextInputTraits protocol defines features associated with keyboard input to a text object. For a custom text object to support keyboard input, it must adopt this protocol to interact properly with the text input management system. The UITextField and UITextView classes automatically support this protocol.

This protocol is made up of only optional methods so if we wanted to handcuff ourselves to only supporting custom input views our control’s implementation could be a lot simpler.  In this example I have also made the tap behaviour part of the control—YMMV:

A pretty unusual use-case but hopefully this little piece of knowledge will prevent you from having to implement this functionality using a hidden UITextField  or UITextInput  as I’ve seen in plenty of codebases.  Example code from this post is available on GitHub.