Custom Views for Data Input

UIKit allows apps to substitute custom input views for the system keyboard. It also enables apps to have an accessory view above the system keyboard or custom input view. Additionally, it enables apps to play key-click sounds when users tap on a controls of an input view or input accessory view.

Input Views and Input Accessory Views

The UIKit framework includes support for custom input views and input accessory views. Your app can substitute its own input view for the system keyboard when users edit text or other forms of data in a view. For example, an app could use a custom input view to enter characters from a runic alphabet. You may also attach an input accessory view to the system keyboard or to a custom input view; this accessory view runs along the top of the main input view and can contain, for example, controls that affect the text in some way or labels that display some information about the text.

To get this feature if your app is using UITextView and UITextField objects for text editing, simply assign custom views to the inputView and inputAccessoryView properties. Those custom views are shown when the text object becomes first responder.

You are not limited to input views and input accessory views in framework-supplied text objects. Any class inheriting directly or indirectly from UIResponder (usually a custom view) can specify its own input view and input accessory view. The UIResponder class declares two properties for input views and input accessory views:

@property (readonly, retain) UIView *inputView;
@property (readonly, retain) UIView *inputAccessoryView;

When the responder object becomes the first responder and inputView (or inputAccessoryView) is not nil, UIKit animates the input view into place below the parent view (or attaches the input accessory view to the top of the input view). The first responder can reload the input and accessory views by calling the reloadInputViews method of UIResponder.

The UITextView class redeclares the inputView and inputAccessoryView properties as readwrite. Clients of UITextView objects need only obtain the input and input-accessory views—either by loading a nib file or creating the views in code—and assign them to their properties. Custom view classes (and other subclasses that inherit from UIResponder) should redeclare one or both of these properties and their backing instance variables and override the getter method for the property—that is, don’t synthesize the properties’ accessor methods. In their getter-method implementations, they should return it the view, loading or creating it if it doesn’t already exist.

You have a lot of flexibility in defining the size and content of an input view or input accessory view. Although the height of these views can be what you’d like, they should be the same width as the system keyboard. If UIKit encounters an input view with a UIViewAutoresizingFlexibleHeight value in its autoresizing mask, it changes the height to match the keyboard. There are no restrictions on the number of subviews (such as controls) that input views and input accessory views may have. For more guidance on input views and input accessory views, see iOS Human Interface Guidelines.

To load a nib file at run time, first create the input view or input accessory view in Interface Builder. Then at runtime get the app’s main bundle and call loadNibNamed:owner:options: on it, passing the name of the nib file, the File’s Owner for the nib file, and any options. This method returns an array of the top-level objects in the nib, which includes the input view or input accessory view. Assign the view to its corresponding property. For more on this subject, see “Nib Files” in Resource Programming Guide.

Listing 7-1 illustrates a custom view class lazily creating its input accessory view in the inputAccessoryView getter method.

Listing 7-1  Creating an input accessory view programmatically

- (UIView *)inputAccessoryView {
    if (!inputAccessoryView) {
        CGRect accessFrame = CGRectMake(0.0, 0.0, 768.0, 77.0);
        inputAccessoryView = [[UIView alloc] initWithFrame:accessFrame];
        inputAccessoryView.backgroundColor = [UIColor blueColor];
        UIButton *compButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        compButton.frame = CGRectMake(313.0, 20.0, 158.0, 37.0);
        [compButton setTitle: @"Word Completions" forState:UIControlStateNormal];
        [compButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
        [compButton addTarget:self action:@selector(completeCurrentWord:)
            forControlEvents:UIControlEventTouchUpInside];
        [inputAccessoryView addSubview:compButton];
    }
    return inputAccessoryView;
}

The subviews of an input view and input accessory view can be anything you want. If they are buttons or other controls, you need to specify targets and actions for each control and implement the associated action methods to perform data input or manipulation.

Just as it does with the system keyboard, UIKit posts UIKeyboardWillShowNotification, UIKeyboardDidShowNotification, UIKeyboardWillHideNotification, and UIKeyboardDidHideNotification notifications. The object observing these notifications can get geometry information related to the input view and input accessory view and adjust the edited view accordingly. See “Keyboards and Input Methods” for examples and related information.

Playing Input Clicks

You can play standard system keyboard clicks when a user taps in your custom input views and keyboard accessory views. First, adopt the UIInputViewAudioFeedback protocol in your input view. Then, call the playInputClick method when responding to a key tap in the view.

Adopting the UIInputViewAudioFeedback Protocol

Perform the following three steps to adopt the UIInputViewAudioFeedback protocol:

  1. In your Xcode project, create a subclass of the UIView class. In the header file, indicate that the subclass conforms to the UIInputViewAudioFeedback protocol, as follows:

    @interface KeyboardAccessoryView : UIView <UIInputViewAudioFeedback> {
    }
  2. In the implementation file for your UIView subclass, implement the enableInputClicksWhenVisible method, as follows:

    - (BOOL) enableInputClicksWhenVisible {
        return YES;
    }
  3. Finally, in the Interface Builder document for your custom input or accessory view, select the View object. In the Identity inspector, set the class for the object to be your UIView subclass.

Playing Input Clicks

To play an input click for a key tap in a custom input or keyboard accessory view, first ensure that view adopts the UIInputViewAudioFeedback protocol as described in “Adopting the UIInputViewAudioFeedback Protocol.” Then, for each tap that you want to provide a click sound for, call the playInputClick method of the UIDevice class, as follows:

- (void) playClickForCustomKeyTap {
   [[UIDevice currentDevice] playInputClick];
}

The system automatically manages the audio session for custom input clicks, including audio ducking as needed. (For information on audio sessions, see Audio Session Programming Guide.)