Replace the system keyboard with a custom keyboard view to customize text field input for your iOS App.
My previous article on Unit Testing added the ability to enter input directly into a calculator's display field using the system keyboard. This was somewhat "contrived" because none of the keyboard types for a UITextField were all that usable. This article fixes that problem by creating a calculator keypad view and associating it with the display field in place of the system keyboard that appears when the field is tapped.
This keypad could be used in a financial app to perform a calculation on the fly without having to show a calculator screen.
Both UITextField and UITextView have a read-write inputView property. We will create a free form view with calculator keys and set it to the inputView, add an accessory view with a button that dismisses the view when tapped, and add playing a click sound when a key is tapped.
The keypad view we create is intended only for the iPhone in Portrait orientation. When the iPhone is in landscape, the inputView should be set to a second keypad with landscape dimensions. Because the four keyboard notifications are posted for the inputView, UIKeyboardWillShowNotification, UIKeyboardDidShowNotification, UIKeyboardWillHideNotification, and UIKeyboardDidHideNotification, the orientation can be calculated and the inputView updated with the appropriate keypad before the keypad appears.
The keyboard notifications can also be used for adjusting the location of the field on the screen to accommodate the keyboard so the user can see what is typed in.
Unit Testing Apps and Frameworks
The first step is the same as my previous blog: download the Unit Testing sample from the Apple Developer site.
Move the UnitTests.zip from the Downloads folder and unzip. Go to the iOS_Calc folder below UnitTests and open the Xcode iOS_Calc project. After opening the project, there may be a few warnings. These are easily fixed (e.g., create the default 568H retina launch image).
The iOS_Calc app is a simple calculator that presents a screen with the typical calculator buttons for adding, subtracting, multiplying, and dividing real numbers. The numbers and each calculator result are displayed in a UITextField. If you tap on the display field the system keyboard appears and you can enter characters, but you are not using the calculator.
Let's create an Interface Builder file that will hold a keypad view for the display field.
In Xcode create a new Xib file by selecting 'New | File ...' from the File menu. From the dialog that appears choose 'User Interface' under iOS in the left-hand column and 'Empty' - an empty Interface Builder document - from the selections on the right. Click 'Next' and keep the default 'iPhone' for device family. Click 'Next' and Keypad for the name and click 'Create'.
Select the Keypad.xib file in the project navigator so that the Interface Builder editor appears in the editor section. From the Objects library in the lower right drag a View into the empty file. So you can resize the view go to the Attributes Inspector and for size select 'Freeform'. For Orientation keep the default 'Portrait'.
Go to the Size inspector and enter 320 for width and 216 for height, respectively. These are the default dimensions of the portrait keyboard, but you may enter a different height. Set the background color (I chose a light gray to look like the Mac's Calculator app) and drag eighteen UIButtons onto the view. To get all the buttons to fit inside the view, set the width and height of each button to 73 and 37, respectively (except for 0 and =). The margin between each button is 5 pixels.
With the view selected, go to the File Inspector and make sure "Use Autolayout" is not selected if your iOS deployment target is less than iOS 6.0.
Select the File's owner on the left-hand side of the editor for the view. Select Identity Inspector and set the owner's class to "CalcViewController."
Next select the Connections Inspector and each one of the eighteen buttons in the view. In the inspector drag a connection from Touch Up Inside to the File's Owner. When you release the mouse, select press: in the popup to make the connection. Now tapping each button invokes the CalcViewController's press: method.
In the Project Navigator select iOS_CalcViewController.m so the file will appear in the editor. Because we are updating the view controller's UI, we first add a viewDidLoad method. In this method we load the view contained in Keypad.xib and set to the display field's inputView. Then we create a "Done" button that will dismiss the keypad when tapped. We add this button to the right side of a toolbar and set the display field's accessory view to the toolbar.
For now we are done with CalcViewController. Next we add playing a click sound when a keypad key is tapped.
Play a click when a key is tapped
To play a click, the keypad's view must implement the UIInputViewAudioFeedback protocol. Select 'New | File ...' from the File menu. From the dialog that appears choose 'Cocoa Touch' under iOS in the left-hand column and 'Objective-C class' from the selections on the right. Click 'Next' and for the name enter 'KeyboardInputView'. It is a subclass of UIView. Click 'Next' and 'Create'.
Add the UIInputViewAudioFeedback protocol declaration to KeyboardInputView.h.
Add the enableInputClicksWhenVisible method to KeyboardInputView.m. This method must return YES.
In the Project Navigator select Keypad.xib so the Keypad view appears in the editor. Select the Keypad view in the editor. In the Identity Inspector set the class for the view to KeyboardInputView. Save the file.
In the Project Navigator select iOS_CalcViewController.m so the file will appear in the editor. Add [[UIDevice current] playInputClick] to the press: method.
Now try it out. Run the app in the simulator or on the device, but only if you run on the device can you hear the key clicks.
A custom keyboard view is one more way you can improve the usability and performance of your app, when you want to customize what the user can enter into a text field or view. For this example you get the added bonus of an app already setup for unit testing.