Input Accessorizing with UIViewController

When designing a user interface that accepts and displays text input, a common
pattern is to have a text field persist on screen. As the only control in the
view, it is immediately clear how to enter text and have it displayed. It
doesn’t hurt that Apple has been training users to accept this pattern for years
in Messages.app.

In iPhone OS 3.2, this type of persistent view that is anchored to the keyboard
became officially supported with the addition of inputAccessoryView to
UIResponder. The documentation for this method encourages subclassing to
support custom input accessory views.

The default value of this property is nil. Subclasses that want to attach
custom controls to either a system-supplied input view (such as the keyboard)
or a custom input view (one you provide in the inputView property) should
redeclare this property as readwrite and use it to manage their custom
accessory view. When the receiver subsequently becomes the first responder,
the responder infrastructure attaches the view to the appropriate input view
before displaying it.

To achieve our desired result we can take advantage of the fact that
UIViewController is a UIResponder subclass. By overriding the
inputAccessoryView and returning an instance of a view, UIViewController
will take care of placing that view at the bottom of the screen and animating it
appropriately when they keyboard appears or disappears.

Assume that we’ve already defined a UIToolbar subclass called
MessageInputAccessoryView to use as our accessory input view. In a real
application, this class would be responsible for adding a text field to its
hierarchy, managing the input and communicating it back up to the view
controller. Implementing such a view is beyond the scope of this post.

The first step to displaying the accessory view is to declare it. We’re going to
declare a global, private constant instance of MessageInputAccessoryView.
Constants declared in the global scope are lazily initialized by default so we
can guarantee that only one instance of this view is ever created and only right
when the view controller asks for it.

privateletaccessoryView=AccessoryView(frame:CGRectZero)

Now we can override inputAccessoryView on MessagesViewController to return
our newly declared accessoryView.

Because this functionality descends from UIResponder, we need to allow
MessagesViewController to become the first responder in the responder chain in
order to interact with the input accessory view. We can do that by overriding
canBecomeFirstResponder() and returning true.

overridefunccanBecomeFirstResponder()->Bool{returntrue}

Putting it all together and our MessagesViewController looks like this.

The Responder
Chain
is a powerful pattern employed across UIKit. As a parent class of both
UIViewController and UIView, it allows us to do some pretty incredible
things with regards to view management and event dispatching. Thanks to this
overlooked feature of UIResponder, all of the tedium of managing a view on
screen that is keyboard-aware is abstracted away and managed by
UIViewController.