In the last post we looked at the basic mechanics of UITextField and how to use it to gather text-based input. By tapping on the UITextField, we saw how iOS automatically brings a virtual keyboard on-screen to accommodate data entry. While the standard keyboard is quite functional, there are many situations in which it simply won’t be flexible enough for your needs. You will often come across situations where you’ll want to take action on the input without dismissing the keyboard. In this post we’ll see how we can add such functionality to the keyboard using custom accessory views.

Extending the TextMe project

We’re going to extend the TextMe project we built in the previous post with the ability to calculate tips, so if you’ve got the project handy, open it up in Xcode now; otherwise you can download the project and then open it in Xcode.

Once you’ve got the project open, click on ViewController.xib to open Interface Builder. Your project should look similar to Figure A.

Figure A

Drag a new label object from the Object Library to the area just above the UITextField and align it with the text field’s left edge. Change the text from “Label” to “Tip:” and change the text color and size to something brighter and larger.

Place another label object just to the right of “Tip:”. Set this label’s text color and size to the same as “Tip:”, and change the text from “Label” to “0.” The result should look similar to Figure B.

Figure B

Now open the Assistant Editor and Control-drag from the second label you created to just under the myTextField property in ViewController.h. Name the new outlet “tipLabel” and click Connect to create a property for the label. (Figure C)

Figure C

Our ultimate goal is to add a toolbar to the keyboard with buttons that can execute custom methods in our class. You may recall from a previous post that virtually all user interface controls in iOS are subclasses of UIView, and such is the case with UIToolbar. Fortunately for us, it just so happens that UITextField has a property named inputAccessoryView that we can use to specify a UIView that will appear just above the standard keyboard when the text field becomes active (i.e. when it is the first responder).

With this bit of information in hand, we have a simple strategy for accomplishing our goal – we will create a toolbar, assign it to the inputAccessoryView property, and let iOS take care of the details of displaying it. As you develop your iOS skills, you will find that knowing the features and functions available in the SDK is often more important than your coding skills. The inputAccessoryView property of UITextField is a perfect example of this.
Take a look at Figure D to get a feel for the custom view we are going to build. The green arrow represents a type of UIBarButtonItem know as a “Flexible Space”. It is invisible, but occupies the unused space in the middle of the toolbar such that it causes the buttons to be nicely aligned at the ends of the toolbar. Instead of using Interface Builder, we’re going to build this view programmatically.

Figure D

Switch back to the Standard Editor and select ViewController.m from the Files and Groups pane.

Change viewDidLoad to look like the version shown below and enter the calculateTip and textFieldDone methods directly below it.

- (void)viewDidLoad
 [super viewDidLoad];
 UIToolbar *tipToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
 tipToolbar.barStyle = UIBarStyleBlackOpaque;
 tipToolbar.items = [NSArray arrayWithObjects:
 // 1
 [[UIBarButtonItem alloc] initWithTitle:@"Calculate"
 // 2
 [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
 // 3
 [[UIBarButtonItem alloc] initWithTitle:@"Done"
 [tipToolbar sizeToFit];
 // 4
 self.myTextField.inputAccessoryView = tipToolbar;
- (void)calculateTip
 // 5
 float mealAmount = [self.myTextField.text floatValue];
 float tip = mealAmount * 0.15;  // 15% tip amount
 self.tipLabel.text = [NSString stringWithFormat:@"$%3.2f",tip];
- (void)textFieldDone
 // 6
 [self.myTextField resignFirstResponder];

Let’s go over what we’ve done. In viewDidLoad the first thing we do is add a new UIToolbar and equip it with buttons. At comment 1, we are adding a button that will execute our calculateTip method. At comment 2, we add the flexible space, and at comment 3, we finish by adding a button to dismiss the keyboard using the textFieldDone method.

At comment 4, we assign our toolbar to the inputAccessoryView property of myTextField. This is all we need to do to have our toolbar appear above the keyboard.

When the Calculate button is pressed, our calculateTip method is fired. At comment 5, we convert the text field value to a floating point number, calculate the tip amount, and then assign that value to tipLabel.text. Note that we convert the number back to a string as we make the assignment.

The Done button and textFieldDone method provide an alternate way to dismiss the keyboard without using the return key. This is much more relevant when using a UITextView, where the return key is used to add new lines to the input text and usually can’t be used to dismiss the keyboard.

We’re now ready to build and run the app. Enter an amount you’re likely to pay for your next lunch and tap Calculate. You should have results similar to Figure E. Also try tapping Done to dismiss the keyboard.

Figure E

Bottom line

The best way to really become an accomplished iOS programmer is to practice, practice, practice, so you might want to try your hand at adding another pair of labels and modify the calculateTip method to show the total meal amount with tip included.

This is just one example of the possibilities of custom accessory views. For example, you could create a button that causes a UIPickerView to appear to let the user choose a date more easily, or perhaps change the style and color of the font in a UITextView. You will find that using a UIToolbar as the basic foundation for a custom accessory view is a very easy and flexible approach to take as you begin to build more advanced functionality into your apps.