Sie sind auf Seite 1von 106

Text Programming Guide for iOS

Contents

About Text Handling in iOS 8


At a Glance 8 The UIKit Framework Provides Your App with Text and Web Objects 9 When Users Edit Text, Your App Must Manage the Keyboard 9 Your App Can Draw and Manage Text Directly 9 Your App Has a Range of Options for the Input and Editing of Data 10 See Also 10

Displaying Text Content in iOS 11


Use Text Objects to Display Text Content 11 Use Web Views to Display Web Content 13

Typographical Concepts 15
Characters and Glyphs 15 Typefaces and Fonts 17 Text Layout 17

Managing Text Fields and Text Views 22


The Sequence of Messages to the Delegate 22 Configuring Text Fields and Text Views 24 Tracking Multiple Text Fields or Text Views 24 Getting the Entered Text and Setting Text 26 Using Formatters with Text Fields 27 Validating Entered Text 29 Using Overlay Views in Text Fields 31 Tracking the Selection in Text Views 33

Displaying Web Content 34


Loading Local Content 34 Loading Content From the Network 34

Managing the Keyboard 37


Keyboards and Input Methods 37 Configuring the Keyboard for Text Objects 37

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

Contents

Configuring the Keyboard for Web Views 39 Managing the Keyboard 40 Receiving Keyboard Notifications 40 Displaying the Keyboard 42 Dismissing the Keyboard 42 Moving Content That Is Located Under the Keyboard 42

Copy, Cut, and Paste Operations 47


Copy-Paste Operations in UIKit 47 Pasteboard Concepts 48 Named Pasteboards 48 Pasteboard Persistence 49 Pasteboard Owner and Items 49 Representations and UTIs 49 Change Count 51 First Steps: Identify the Selection and Display the Edit Menu 51 Copying and Cutting the Selection 51 Pasting the Selection 53 Ending an Operation 54

Custom Views for Data Input 55


Input Views and Input Accessory Views 55 Playing Input Clicks 57 Adopting the UIInputViewAudioFeedback Protocol 57 Playing Input Clicks 58

Displaying and Managing the Edit Menu 59


Managing the Selection and the Edit Menu 59 Adding Custom Items to the Edit Menu 62 Dismissing the Edit Menu 63

Using Text Kit to Draw and Manage Text 64


Primary Text Kit Objects 65 Text Attributes 66 Character Attributes 66 Paragraph Attributes 67 Document Attributes 67 Attribute Fixing 67 Changing Text Storage Programmatically 68 Working with Font Objects 68

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

Contents

Text Styles 69 Font Descriptors 70 Querying Font Metrics 72 Laying Out Text 73 The Layout Process 73 Generating Line Fragment Rectangles 74 Specifying Exclusion Paths 74 Specifying Multipage and Multicolumn Layouts 75

Lower Level Text-Handling Technologies 79


Simple Text Drawing 79 Core Text 80 Core Text Layout Opaque Types 80 Core Text Font Opaque Types 81 Core Graphics Text Drawing 82 Foundation-Level Regular Expressions 82 ICU Regular-Expression Support 84 Simple Text Input 85 Communicating with the Text Input System 86 Overview of the Client Side of Text Input 87 A Guided Tour of a UITextInput Implementation 91 Spell Checking and Word Completion 102

Document Revision History 105

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

Figures, Tables, and Listings

Displaying Text Content in iOS 11


Figure 1-1 Figure 1-2 Text classes in the UICatalog app 12 A web view 14

Typographical Concepts 15
Figure 2-1 Figure 2-2 Figure 2-3 Figure 2-4 Figure 2-5 Figure 2-6 Figure 2-7 Glyphs of the character A 15 Ligatures 16 Fonts in the Times font family 17 Glyph metrics 19 Kerning 19 Alignment of text relative to margins 20 Justified text 21

Managing Text Fields and Text Views 22


Listing 3-1 Listing 3-2 Listing 3-3 Listing 3-4 Listing 3-5 Listing 3-6 Listing 3-7 Listing 3-8 Listing 3-9 Listing 3-10 Listing 3-11 Listing 3-12 Identifying the passed-in text object using an outlet 24 Identifying the passed-in text object using tags 25 Getting the text entered into a text field 26 Getting the text entered into a text view 27 Configuring a date formatter 28 Using an NSDateFormatter object to convert a date string to a date object 28 Validating the format of a text fields string using a regular expression 29 Validating a text views string for allowable length 30 Validating each character as its entered 30 Displaying an overlay view in a text field 32 Removing the overlay view 32 Getting the selected substring and changing it 33

Displaying Web Content 34


Listing 4-1 Listing 4-2 Listing 4-3 Loading a local PDF file into the web view 34 The web-view delegate managing network loading 35 Stopping a load request when the web view is to disappear 36

Managing the Keyboard 37


Figure 5-1 Several different keyboard types 38

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

Figures, Tables, and Listings

Figure 5-2 Figure 5-3 Figure 5-4 Listing 5-1 Listing 5-2 Listing 5-3

Several different keyboards and input methods 39 Relative keyboard sizes in portrait and landscape modes 41 Adjusting content to accommodate the keyboard 43 Handling the keyboard notifications 44 Additional methods for tracking the active text field. 45 Adjusting the frame of the content view and scrolling a field above the keyboard 46

Copy, Cut, and Paste Operations 47


Figure 6-1 Listing 6-1 Listing 6-2 Pasteboard items and representations 50 Copying and cutting operations 52 Pasting data to a selection 54

Custom Views for Data Input 55


Listing 7-1 Creating an input accessory view programmatically 56

Displaying and Managing the Edit Menu 59


Figure 8-1 Listing 8-1 Listing 8-2 Listing 8-3 An edit menu with a custom menu item 62 Displaying the edit menu 60 Conditionally enabling menu commands 61 Implementing a Change Color menu item 62

Using Text Kit to Draw and Manage Text 64


Figure 9-1 Figure 9-2 Figure 9-3 Figure 9-4 Figure 9-5 Figure 9-6 Figure 9-7 Figure 9-8 Figure 9-9 Table 9-1 Table 9-2 Listing 9-1 Listing 9-2 Listing 9-3 Text Kit Framework Position 64 Primary Text Kit Objects 65 Composition of an attributed string 66 Font metrics 72 Line fragment fitting 75 Object configuration for a single text flow 75 Object configuration for paginated text 76 Object configuration for multicolumn text 77 Object configuration for multiple views of the same text 78 Text style constants 69 Font metrics and related UIFont methods 72 Font family name matching 70 Font trait modification 71 Object creation for a single text flow 75

Lower Level Text-Handling Technologies 79


Figure 10-1 Figure 10-2 Core Text layout objects 81 Paths of communication with the text input system 88

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

Figures, Tables, and Listings

Listing 10-1 Listing 10-2 Listing 10-3 Listing 10-4 Listing 10-5 Listing 10-6 Listing 10-7 Listing 10-8 Listing 10-9 Listing 10-10 Listing 10-11 Listing 10-12 Listing 10-13 Listing 10-14 Listing 10-15 Listing 10-16 Listing 10-17 Listing 10-18

Finding a substring using a regular expression 83 Implementing simple text entry 85 Declaring the IndexedPosition and IndexedRange classes 92 Implementing the IndexedPosition and IndexedRange classes 92 Inserting text input into storage and updating selected and marked ranges 94 Implementations of textInRange: and replaceRange:withText: 95 Returning ranges of selected and marked text 96 Setting the range of selected text and setting the marked text 96 Implementing positionFromPosition:offset: 98 Implementing offsetFromPosition:toPosition: 98 Implementing textRangeFromPosition:toPosition: 98 An implementation of firstRectForRange: 99 Mapping text range to enclosing rectangle 99 An implementation of closestPositionToPoint: 100 Mapping a point to a character index 100 Sending messages to the text input delegate 101 Spell-checking a document 102 Presenting a list of word completions for the current partial string 104

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

About Text Handling in iOS

The iOS platform gives you many ways to display text in your apps and let users edit that text. It also lets you display formatted text and web content in your apps views. The resources at your disposal range from framework objectssuch as text views, text fields, and web viewsto text layout engines that you can use directly to draw, lay out, and otherwise manage text.

With the classes in the UIKit framework, you can manage the edit menu (including adding custom items to it), implement custom input views, and copy, cut, and paste data within and between apps. Note: This document was previously titled Text, Web, and Editing Programming Guide for iOS .

At a Glance
Apps in iOS have a number of powerful technologies to handle text, both for editing text and for rendering high-quality typographically formatted text.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

About Text Handling in iOS At a Glance

The UIKit Framework Provides Your App with Text and Web Objects
You can add ready-made text views, text fields, and labels to your apps user interface by using instances of the UITextView, UITextField, and UILabel. You can add and configure them programmatically or by using the Interface Builder editor in Xcode. You can also turn a view of your app into a miniature web browser capable of understanding and displaying HTML, CSS, and JavaScript content. You do this using a UIWebView object. Relevant Chapters: Displaying Text Content in iOS (page 11), Typographical Concepts (page 15), Managing Text Fields and Text Views (page 22), Displaying Web Content (page 34)

When Users Edit Text, Your App Must Manage the Keyboard
When a user taps a text field, text view, or form field in a web view, iOS animates a keyboard into view. An app can control which keyboard is presented; for example, for a numeric-value field, the app should select the numeric keypad. If the entered or edited text is obscured by the keyboard, the app should adjust the view displaying the text so that the text appears above the keyboard. The delegate of a text view, text field, or web view is responsible for validating edited text and for accessing and storing edited text when the user dismisses the keyboard. Relevant Chapters: Managing the Keyboard (page 37)

Your App Can Draw and Manage Text Directly


Underlying the text views in UIKit is a powerful layout engine called Text Kit. If you need to customize the layout process or you need to intervene in that behavior, you can use Text Kit. Text Kit is a set of classes and protocols that provide high-quality typographical services which enable apps to store, lay out, and display text with all the characteristics of fine typesetting, such as kerning, ligatures, line breaking, and justification. For most apps, you can use the high-level text display classes and Text Kit for all their text handling. For smaller amounts of text and special needs requiring custom solutions, you can use alternate, lower level technologies, such as the programmatic interfaces from the Core Text, Core Graphics, and Core Animation frameworks as well as other APIs in UIKit itself. To communicate directly with the text-input system of iOS, implement the UITextInput protocol and related protocols and classes. Your app can also make use of technologies for spell checking and regular expressions.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

About Text Handling in iOS See Also

Relevant Chapter: Using Text Kit to Draw and Manage Text (page 64), Lower Level Text-Handling Technologies (page 79)

Your App Has a Range of Options for the Input and Editing of Data
The UIKit framework includes programmatic interfaces for editing the data in a view and for entering data into an app. Custom input views can replace the system keyboard to permit input of special data; input accessory views are a custom view above the system keyboard (or custom input view) that enables users to affect edited data in app-specific ways. Using UIPasteboard and related classes, an app can copy, cut, and paste data within different locations of itself or between itself and another app. As part of copy-cut-paste operations, the user taps a command on an contextual edit menu; your app manages this menu and can add custom commands to it. Relevant Chapters:: Copy, Cut, and Paste Operations (page 47), Displaying and Managing the Edit Menu (page 59), Custom Views for Data Input (page 55)

See Also
The Core Graphics and Core Animation frameworks have some text-handling capabilities. Core Animation, for example, offers the CATextLayer class. To learn more about these capabilities, read Quartz 2D Programming Guide (Core Graphics) and Core Animation Programming Guide . To find out more about the Core Text framework, which is apropriate for developing higher-level text-handling frameworks, read Core Text Programming Guide and Core Text Reference Collection .

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

10

Displaying Text Content in iOS

The text system in iOS provides a tremendous amount of power while still being very simple to use. The UIKit framework includes several high-level classes for managing the display and input of text. UIKit also includes a class for displaying HTML, CSS, and JavaScript-based web content.

Use Text Objects to Display Text Content


Text objects display styled, formatted text in a range of fonts, styles, and sizes. The UIKit framework provides three primary classes for displaying this text content in an apps user interface:

UILabel defines a label, which displays a static text string. UITextField defines a text field, which displays a single line of editable text. UITextView defines a text view, which displays multiple lines of editable text.

Although these classes actually can support the display of arbitrary amounts of text, labels and text fields are intended to be used for relatively small amounts of text, typically a single line. Text views, on the other hand, are meant to display large amounts of text. Text view objects, created from the UITextView class, display text formatted into paragraphs, columns, and pages, with all the characteristics of fine typesetting, such as kerning, ligatures, sophisticated line-breaking, and justification. These typographic services are supplied to UITextView through an underlying technology called Text Kit, a powerful layout engine that is both easy to use and extensible. See Using Text Kit to Draw and Manage Text (page 64) for more information about Text Kit.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

11

Displaying Text Content in iOS Use Text Objects to Display Text Content

Figure 1-1 shows examples of the primary text objects as they appear on screen. The image on the left shows several different styles of text fields while the image on the right shows a single text view. The callouts displayed on the background are UILabel objects embedded inside the table cells used to display the different views. (These examples were taken from the UICatalog sample app, which demonstrates many of the views and controls available in UIKit.)
Figure 1-1 Text classes in the UICatalog app

When working with editable text fields and text views, you should always provide a delegate object to manage the editing session. Text views send several different notifications to the delegate to let them know when editing begins, when it ends, and to give them a chance to override some editing actions. For example, the delegate can decide if the current text contains a valid value and prevent the editing session from ending if it does not. When editing does finally end, you also use the delegate to get the resulting text value and update your apps data model. Because there are slight differences in their intended usage, the delegate methods for each text view are slightly different. A delegate that supports the UITextField class implements the methods of the UITextFieldDelegate protocol. Similarly, a delegate that supports the UITextView class implements the methods of the UITextViewDelegate protocol. In both cases, you are not required to implement any of the protocol methods, but if you do not, the text field or view is not as useful.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

12

Displaying Text Content in iOS Use Web Views to Display Web Content

Managing Text Fields and Text Views (page 22) describes the sequence of delegation messages for both text fields and text views and discusses various tasks performed by the delegates of these objects. For more information about the methods of the UITextFieldDelegate and UITextViewDelegate protocols, see UITextFieldDelegate Protocol Reference and UITextViewDelegate Protocol Reference .

Use Web Views to Display Web Content


A web view object displays web-based content. It is an instance of the UIWebView class that enables you to integrate what is essentially a miniature web browser into your apps user interface. The UIWebView class makes full use of the same web technologies used to implement Safari in iOS, including full support for HTML, CSS, and JavaScript content. The class also supports many of the built-in gestures that users are familiar with in Safari. For example, you can double-click and pinch to zoom in and out of the page and you can scroll around the page by dragging your finger. In addition to displaying content, you can also use a web view object to gather input from the user through the use of web forms. Like the other text classes in UIKit, if you have an editable text field on a form in your web page, tapping that field brings up a keyboard so that the user can enter text. Because it is an integral part of the web experience, the web view itself manages the displaying and dismissing of the keyboard for you.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

13

Displaying Text Content in iOS Use Web Views to Display Web Content

Figure 1-2 shows an example of a UIWebView object from the UICatalog sample app, which demonstrates many of the views and controls available in UIKit. Because it just displays HTML content, if you want the user to be able to navigate pages much like they would in a web browser, you need to add controls to do so.
Figure 1-2 A web view

A web view provides information about when pages are loaded, and whether there were any load errors, through its associated delegate object. A web delegate is an object that implements one or more methods of the UIWebViewDelegate protocol. Your implementations of the delegate methods can respond to failures or perform other tasks related to the loading of a web page. Displaying Web Content (page 34) describes how to display HTML and other content in a web view.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

14

Typographical Concepts

This chapter defines some important typographical concepts relevant to the text system. Many of the terms representing these concepts are reflected in text system APIs. If youre familiar with typography, you can skip this chapter.

Characters and Glyphs


A character is the smallest unit of written language that carries meaning. Characters can correspond to a particular sound in the spoken form of the language, as do the letters of the roman alphabet; they can represent entire words, such as Chinese ideographs; or they can represent independent concepts, such as mathematical symbols. In every case, however, a character is an abstract concept. Although characters must be represented in a display area by a recognizable shape, they are not identical to that shape. That is, a character can be drawn in various forms and remain the same character. For example, an uppercase A character can be drawn with a different size or a different stroke thickness, it can lean or be vertical, and it can have certain optional variations in form, such as serifs. Any one of these various concrete forms of a character is called a glyph. Figure 2-1 shows different glyphs that all represent the character uppercase A. glyph_a.eps
Figure 2-1 Glyphs of the character A
Cocoa_Text_Architecture Apple, Inc.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

15

Typographical Concepts Characters and Glyphs

Characters and glyphs do not have a one-to-one correspondence. In some cases a character may be represented by multiple glyphs, such as an which may be an e glyph combined with an acute accent glyph . In other cases, a single glyph may represent multiple characters, as in the case of a ligature, or joined letter. Figure 2-2 shows individual characters and the single-glyph ligature often used when they are adjacent.
Figure 2-2 Ligatures

A ligature is an example of a contextual form in which the glyph used to represent a character changes depending on the characters next to it. Other contextual forms include alternate glyphs for characters beginning or ending a word. Computers store characters as numbers mapped by encoding tables to their corresponding characters. The encoding scheme native to iOS and OS X conforms to the Unicode standard. Unicode provides a standard methodology for assigning a unique number for every character in every modern written language in the world, independent of the platform, program, and programming language being used. This universal standard solves a longstanding problem of different computer systems using hundreds of conflicting encoding schemes. It also provides information specifying how to handle bidirectional text and contextual forms; how to form words and break lines; how to sort text in different languages; and how to format numbers, dates, times, and other elements appropriate to different languages. Glyphs are also represented by numeric codes called glyph codes. The glyphs used to depict characters are selected by the layout manager during composition and layout processing. The layout manager determines which glyphs to use and where to place them in the display, or view. The layout manager caches the glyph codes in use and provides methods to convert between characters and glyphs and between characters and view coordinates.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

16

Typographical Concepts Typefaces and Fonts

Typefaces and Fonts


A typeface is a set of visually related shapes for some or all of the characters in a written language. For example, Times is a typeface, designed by Stanley Morrison in 1931 for The Times newspaper of London. All of the letter forms in Times are related in appearance, having consistent proportions between stems (vertical strokes) and counters (rounded shapes in letter bodies) and other elements. When laid out in blocks of text, the shapes in a typeface work together to enhance readability. A typestyle, or simply style, is a distinguishing visual characteristic of a typeface. For example, roman typestyle is characterized by upright letters having serifs and stems thicker than horizontal lines. In italic typestyle, the letters slant to the right and are rounded, similar to cursive or handwritten letter shapes. A typeface usually has several associated typestyles. A font is a series of glyphs depicting the characters in a consistent size, typeface, and typestyle. A font is intended for use in a specific display environment. Fonts contain glyphs for all the contextual forms, such as ligatures, as well as the normal character forms. A font family is a group of fonts that share a typeface but differ in typestyle. So, for example, Times is the name of a font family (as well as the name of its typeface). Times roman and Times Italic are the names of two individual fonts belonging to the Times family. Figure 2-3 shows several of the fonts in the Times font family.
Figure 2-3 Fonts in the Times font family

Styles, also called traits , include variations such as bold, italic, condensed, expanded, narrow, small caps, poster fonts, and fixed pitch. The text system includes objects called font descriptors, which provide font-matching capability, so that you can partially describe a font by creating a font descriptor with, for example, just a family name or weight, and you can then find all the fonts on the system that match the given trait.

Text Layout
Text layout is the process of arranging glyphs on a display device, in an area called a text view , which represents an area similar to a page in traditional typesetting. The order in which glyphs are laid out relative to each other is called text direction. In English and other languages derived from Latin, glyphs are placed side by side to

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

17

Typographical Concepts Text Layout

form words that are separated by spaces. Words are laid out in lines beginning at the top left of the text view proceeding from left to right until the text reaches the right side of the view. Text then begins a new line at the left side of the view under the beginning of the previous line, and layout proceeds in the same manner to the bottom of the text view. In other languages, glyph layout can be quite different. For example, some languages lay out glyphs from right to left or vertically instead of horizontally. It is common, especially in technical writing, to mix languages with differing text direction, such as English and Hebrew, in the same line. Some writing systems even alternate layout direction in every other line (an arrangement called boustrophedonic writing). Some languages do not group glyphs into words separated by spaces. Moreover, some apps call for arbitrary arrangements of glyphs; for example, in a graphic design context, a layout may require glyphs to be arranged on a nonlinear path. To create lines from a string of glyphs, the layout engine must perform line breaking by finding a point at which to end one line and begin the next. In the text system, you can specify line breaking at either word or glyph boundaries. In roman text, a word broken between glyphs requires insertion of a hyphen glyph at the breakpoint. The layout manager lays out glyphs along an invisible line called the baseline. In roman text, the baseline is horizontal, and the bottom edge of most of the glyphs rest on it. Some glyphs extend below the baseline, including those for characters like g that have descenders, or tails, and large rounded characters like O that must extend slightly below the baseline to compensate for optical effects. Other writing systems place glyphs below or centered on the baseline. Every glyph includes an origin point that the layout manager uses to align it properly with the baseline. Glyph designers provide a set of measurements with a font, called metrics, which describe the spacing around each glyph in the font. The layout manager uses these metrics to determining glyph placement. In horizontal text, the glyph has a metric called the advance width, which measures the distance along the baseline to the origin point of the next glyph. Typically there is some space between the origin point and the left side of the glyph, which is called the left-side bearing. There may also be space between the right side of the glyph and the point described by the advance width, which is called the right-side bearing. The vertical dimension of the glyph is provided by two metrics called the ascent and the descent. The ascent is the distance from the

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

18

Typographical Concepts Text Layout

origin (on the baseline) to the top of the tallest glyphs in the font. The descent, which is the distance below the baseline to the bottom of the fonts deepest descender. The rectangle enclosing the visible parts of the glyph is called the glyphterms.eps bounding rectangle or bounding box. Figure 2-4 illustrates these metrics.
Figure 2-4 Glyph metrics
Cocoa_Text_Architecture Apple, Inc.

By default, in horizontal text, typesetters place glyphs side-by-side using the advance width, resulting in a standard interglyph space. However, in some combinations, text is made more readable by kerning, which is shrinking or stretching the space between two glyphs. A very common example of kerning occurs between an uppercase W and uppercase A, as shown in Figure 2-5. Type designers include kerning information in the metrics for a font. The text system provides methods to turn kerning off, use the default settings provided with the font, or tighten or loosen the kerning throughout a selection of text. kerning.eps
Cocoa_Text_Architecture Apple, Inc.

Figure 2-5

Kerning

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

19

Typographical Concepts Text Layout

Type systems usually measure font metrics in units called points, which measure exactly 72 per inch in most computer typesetting systems. Adding the distance of the ascent and the descent of a font provides the fonts point size. Space added during typesetting between lines of type is called leading, after the slugs of lead used for that purpose in traditional metal-type page layout. The total amount of ascent plus descent plus leading provides a fonts line height. (Leading is sometimes also called linegap . It is often specified as a ratio of a fonts point size over the line height at which a block of text is set, such as 14/16.5.) Although the preceding typographic concepts of type design may be somewhat esoteric, most people who have created documents on a computer or typewriter are familiar with the elements of text layout on a page. For example, the margins are the areas of white space between the edges of the page and the text area where the layout engine places glyphs. Alignment describes the way text lines are placed relative to the margins. For example, horizontal text can be aligned right, left, or centered, as shown in Figure 2-6.
Figure 2-6 Alignment of text relative to margins

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

20

Typographical Concepts Text Layout

Lines of text can also be justified; for horizontal text the lines are aligned on both right and left margin by varying interword and interglyph spacing, as shown in Figure 2-7. The system performs alignment and justification, if requested, after the text stream has been broken into lines and hyphens added and other glyph substitutions made. justified.eps
Figure 2-7 Justified text
Cocoa_Text_Architecture Apple, Inc.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

21

Managing Text Fields and Text Views

Text fields and text views have two main functions: to display text and to enable the entry and editing of text. Several programming tasks are associated with these simple purposes, including configuring the text object, accessing the current text, validating what the user enters, and displaying overlay views such as bookmark buttons in text fields. The delegate of a UITextField or UITextView object is responsible for most of these tasks. The delegate must adopt the UITextFieldDelegate or UITextViewDelegate protocols and implement one or more of the protocol methods. Implementation of all protocol methods is optional. To have these methods called, you must set the delegate properties of text fields and text views either programmatically or in Interface Builder.

The Sequence of Messages to the Delegate


In most cases, instances of the UITextField or UITextView classes send a sequence of similarly named messages to their delegates when there is a change (or impending change) in first-responder status for a given text object. When the user taps a text object, it automatically becomes first responder; as a result, the system displays the keyboard and an editing session begins for that text object. When the user taps another text object or taps a button to end editing, the current text object resigns first-responder status. If no other text object is selected, the system hides the keyboard; if, on the other hand, the user selects another text object, it becomes first responder and the keyboard for that object is displayed. There are a couple of exceptions to this common behavior. On the iPad, if a view controller modally presents its view using the "form sheet" style, the keyboard, once shown, is not hidden until the user taps the dismiss key or the modal view controller is programmatically dismissed. The purpose of this behavior is to avoid excessive animations as a user moves between views that are largely, but not entirely, text fields. Another exception involves custom input views. An input view is a substitute for system keyboards that is assigned to the inputView property of a text view or a custom view. When there are input views, UIKit might swap out the keyboard even when a text object is first responder, and it might show a keyboard-like input view on the developer's behalf for non-text objects. The sequence of messages that both text views and text fields send to their delegates is as follows:
1.

Just before a text object becomes first respondertextFieldShouldBeginEditing: (text field) and textViewShouldBeginEditing: (text view).

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

22

Managing Text Fields and Text Views The Sequence of Messages to the Delegate

The delegate can verify whether the text object should become first responder by returning YES (the default) or NO.
2.

Just after a text object becomes first respondertextFieldDidBeginEditing: (text field) and textViewDidBeginEditing: (text view). The delegate can respond to this message by updating state information or, for example, by showing an overlay view during the editing session.

3.

During the editing sessionvarious. While the user enters and edits text, the text object invokes certain delegation methods (if implemented). For example, the delegate of a text view can receive a textViewDidChange: message when any text changes. The delegate of a text field can receive a textFieldShouldClear: message when the user taps the clear button of a text field; the delegate returns a Boolean value indicating whether the text should be cleared.

4.

Just before a text object resigns first respondertextFieldShouldEndEditing: (text field) and textViewShouldEndEditing: (text view). The primary reason for a delegate to implement these methods is to validate entered text. For example, if text should conform to a given format, the delegate validates the entered string here and returns NO if the string does not conform. The default return value is YES. A related method for text fields is textFieldShouldReturn:. When the user taps the return key, the text field class sends a textFieldShouldReturn: message to the delegate to ask whether it should resign first responder.

5.

Just after text a object resigns first respondertextFieldDidEndEditing: (text field) and textViewDidEndEditing: (text view). A delegate can implement these methods to get the text that the user has just entered or edited.

Objects other than the delegate can be informed of changes in the first-responder status of text views and text fields by observing notifications. (They cant, however, approve or deny the transition to a new status.) The notifications have names such as UITextFieldTextDidBeginEditingNotification, UITextViewTextDidEndEditingNotification, and UITextViewTextDidChangeNotification. As with textFieldDidEndEditing: and textViewDidEndEditing:, the primary reason for observing and handling the UITextFieldTextDidEndEditingNotification and UITextViewTextDidEndEditingNotification notifications is to access the text in the associated text field or text view. See UITextField Class Reference and UITextView Class Reference to learn more about the notifications posted by these classes.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

23

Managing Text Fields and Text Views Configuring Text Fields and Text Views

Configuring Text Fields and Text Views


As with any view object provided by the UIKit framework, you usually need to configure text fields and text views before theyre displayed. You can configure them either programmatically or using the attribute inspector of Interface Builder. In either case, you are setting a property of the text object. Some properties are common to text views and text fields, and others are specific to each type of object, including the following:

Text characteristicsText color, alignment, font family, font typeface, and font size. KeyboardKeyboard type, return key name, secure text entry, and auto-enabled return key, all of which are declared by the UITextInputTraits protocol. (Note that an auto-enabled return key associated with a text view acts as a carriage-return key when tapped.) For more information, see Configuring the Keyboard for Text Objects (page 37). Text-field specificBorder, background image, disabled image, clear button, and placeholder text. As a UIControl object, text fields also have highlighted, selected, enabled, and other properties. Text-view specificEditable status, data detectors (for phone numbers and URL links). Because a text view inherits from UIScrollView, you can also manage scroll-view behavior by setting the appropriate properties.

Tracking Multiple Text Fields or Text Views


All methods of the UITextFieldDelegate or UITextViewDelegate protocols have a parameter that identifies the text field or text view with the change in first-responder status, the change in value, or any other change that is the reason for the delegation message. If there is only one text object in the currently displayed view, the identity of the text object referenced by the parameter is obvious. However, if the currently displayed view has multiple text fields or text views, the delegate must find a way to identify the text object that is the subject of a delegation message. You can make this determination using one of two approaches: outlets or tags. For the outlet approach, declare an outlet instance variable (using the IBOutlet keyword) and then make an outlet connection. In your delegation method, test whether the passed-in text object is the same object referenced by the outlet, using pointer comparison. For example, say you declare and connect an outlet named SSN. Your code might look something like Listing 3-1.
Listing 3-1 Identifying the passed-in text object using an outlet

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField { if (textField == SSN) {

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

24

Managing Text Fields and Text Views Tracking Multiple Text Fields or Text Views

// ..... return NO; } return YES; }

Defining outlet connections for the text objects in a view is especially useful, even essential, when you need to write string values to these objects, not just obtain them. For the tag approach, declare a set of enum constants, one constant for each tag.
enum { NameFieldTag = 0, EmailFieldTag, DOBFieldTag, SSNFieldTag };

Then assign the integer value to the tag property of the text object, either programmatically or in the attribute inspector of Interface Builder. (The tag property is declared by UIView.) In a delegation method, you can use a switch statement to evaluate the tag value of the passed-in text object and proceed accordingly (as shown in Listing 3-2).
Listing 3-2 Identifying the passed-in text object using tags

- (void)textFieldDidEndEditing:(UITextField *)textField {

switch (textField.tag) { case NameFieldTag: // do something with this text field break; case EmailFieldTag: // do something with this text field break; // remainder of switch statement.... } }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

25

Managing Text Fields and Text Views Getting the Entered Text and Setting Text

Getting the Entered Text and Setting Text


After a user enters or edits text in a text field or text view and the editing session ends, the delegate should get the text and store it in the apps data model. The best delegation methods for accessing entered text are textFieldDidEndEditing: (text fields) and textViewDidEndEditing: (text views). Listing 3-3 illustrates how you might get text the user has entered in a text field (differentiating among multiple text fields in a view using tags). The text property of UITextField or UITextView holds the string currently displayed by the text object. The delegate gets the string from this property and stores it in a dictionary object using a key defined for each field. If the text field has no string valuethat is, the field holds an empty stringthe delegate simply returns.
Listing 3-3 Getting the text entered into a text field

- (void)textFieldDidEndEditing:(UITextField *)textField { if ([textField.text isEqualToString:@""]) return;

switch (textField.tag) { case NameFieldTag: [thePerson setObject:textField.text forKey:MyAppPersonNameKey]; break; case EmailFieldTag: [thePerson setObject:textField.text forKey:MyAppPersonEmailKey]; break; case SSNFieldTag: [thePerson setObject:textField.text forKey:MyAppPersonSSNKey]; break; default: break; } }

Listing 3-4 shows an implementation of the textViewDidEndEditing: method that gets the displayed string from the text view and stores it in a dictionary. Here the method doesnt ask the text view to resign first responder. (The resignFirstResponder method was called earlier in an action method invoked when the user tapped a Done button in the views user interface.)

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

26

Managing Text Fields and Text Views Using Formatters with Text Fields

Listing 3-4

Getting the text entered into a text view

- (void)textViewDidEndEditing:(UITextView *)textView { NSString *theText = textView.text; if (![theText isEqualToString:@""]) { [thePerson setObject:theText forKey:MyAppPersonNotesKey]; } doneButton.enabled = NO; }

If you need to write string values to text objectsusually after retrieving them from the apps data modelsimply assign the strings to the text property of the text object. For example:
NSString *storedValue = [thePerson objectForKey:MyAppPersonEmailKey]; emailField.text = storedValue;

To do this, its useful to define outlets for each text field or text view that you want to write string values to (emailField, in this example).

Using Formatters with Text Fields


Formatter objects automatically parse strings in a specific format and convert the string to an object representing a number, date, or other value; they also work in reverse, converting NSDate, NSNumber, and similar objects to a formatted string that represents those object values. The Foundation framework provides the abstract base class NSFormatter and two concrete subclasses of that class, NSDateFormatter and NSNumberFormatter. Using these classes, users can enter values such as the following into a text field:
11/15/2010 -1,348.09

And your app can use formatter objects to convert the strings into an NSDate object and an NSNumber object, respectively. The following code listings use a date-formatter object to illustrate the use of formatters. (Of course, you could use a UIDatePicker object for date input rather than a text field, but a text field with an attached date formatter is another option.) The code in Listing 3-5 creates an NSDateFormatter object and assigns it to an

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

27

Managing Text Fields and Text Views Using Formatters with Text Fields

instance variable. It configures the date formatter to use the short style for dates, but in a way that is responsive to changes in calendar, locale, and time zone. It also assigns todays date in the given format as a placeholder string so that users have a model to follow when they enter dates.
Listing 3-5 Configuring a date formatter

- (void)viewDidLoad { [super viewDidLoad]; dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setGeneratesCalendarDates:YES]; [dateFormatter setLocale:[NSLocale currentLocale]]; [dateFormatter setCalendar:[NSCalendar autoupdatingCurrentCalendar]]; [dateFormatter setTimeZone:[NSTimeZone defaultTimeZone]]; [dateFormatter setDateStyle:NSDateFormatterShortStyle]; // example: 4/13/10 DOB.placeholder = [NSString stringWithFormat:@"Example: %@", [dateFormatter stringFromDate:[NSDate date]]];

// code continues.... }

After you have configured the date formatter, the delegate can call the dateFromString: method on the formatter to convert the entered date string into an NSDate object, as shown in Listing 3-6.
Listing 3-6 Using an NSDateFormatter object to convert a date string to a date object

- (void)textFieldDidEndEditing:(UITextField *)textField { [textField resignFirstResponder]; if ([textField.text isEqualToString:@""]) return; switch (textField.tag) { case DOBField: NSDate *theDate = [dateFormatter dateFromString:textField.text];; if (theDate) [inputData setObject:theDate forKey:MyAppPersonDOBKey]; break; // more switch case code here... default:

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

28

Managing Text Fields and Text Views Validating Entered Text

break; } }

The use of formatters does not guarantee that the entered string contains valid valuesfor example, a user could enter 13 for a month number in the Gregorian calendar. To ensure that the user has entered a correct value, the delegate must validate the string as explained in Validating Entered Text (page 29). And because validation often requires a known format and range of valid values, if you configure the date formatter as in Listing 3-5 so that it is sensitive to different calendars and locales, the format cannot be known with certainty. To specify a known date format, configure the date formatter by calling setDateFormat:, passing in a format pattern defined by the Unicode standard. You can also reverse the procedure shown above: Convert a date object to a string in a given format by calling the NSDateFormatter method stringFromDate: and then assign that string to the text property of a text field, text view, or label. For more information on NSDateFormatter and NSNumberFormatter, see Data Formatting Guide .

Validating Entered Text


An app sometimes cannot accept the strings entered in text fields and text views without validating the value first. Perhaps the string must be in a certain format, or the value (after it is converted to a numeric value) must fall within a certain range. The best delegation methods for validating entered strings are textFieldShouldEndEditing: for text fields and textViewShouldEndEditing: for text views. These methods are called just before the text field or text view resigns first responder status. Returning NO prevents that from happening, and consequently the text object remains the focus of editing. If an entered string is invalid, you should also display an alert to inform the user of the error. Listing 3-7 uses a regular expression to verify that the string entered in a Social Security Number field conforms to the format for such numbers.
Listing 3-7 Validating the format of a text fields string using a regular expression

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField { if (textField == SSN) { // SSN is an outlet NSString *regEx = @"[0-9]{3}-[0-9]{2}-[0-9]{4}"; NSRange r = [textField.text rangeOfString:regEx options:NSRegularExpressionSearch]; if (r.location == NSNotFound) {

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

29

Managing Text Fields and Text Views Validating Entered Text

UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error" message:@"Enter social security number in 'NNN-NN-NNNN' format" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease]; [av show]; return NO; } } return YES; }

The implementation of textViewShouldEndEditing: in Listing 3-8 enforces a character limit for the text entered in a text view.
Listing 3-8 Validating a text views string for allowable length

- (BOOL)textViewShouldEndEditing:(UITextView *)textView { if (textView.text.length > 50) { UIAlertView *av = [[[UIAlertView alloc] initWithTitle:@"Entry Error" message:@"You must enter less than 50 characters." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:@"Clear", nil] autorelease]; [av show]; return NO; } return YES; }

The delegate can also validate each character as it is entered into a text field by implementing the textField:shouldChangeCharactersInRange:replacementString: method. The code in Listing 3-9 verifies that each entered character (string) represents a digit. (You could accomplish the same goal by specifying a UIKeyboardTypeNumberPad keyboard for the text field.)
Listing 3-9 Validating each character as its entered

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

30

Managing Text Fields and Text Views Using Overlay Views in Text Fields

replacementString:(NSString *)string { if ([string isEqualToString:@""]) return YES; if (textField.tag == SalaryFieldTag) { unichar c = [string characterAtIndex:0]; if ([[NSCharacterSet decimalDigitCharacterSet] characterIsMember:c]) { return YES; } else { return NO; } }

return YES; }

You can also implement the textField:shouldChangeCharactersInRange:replacementString: method to offer possible word completions or corrections to the user as they enter text.

Using Overlay Views in Text Fields


Overlay views are small views inserted into the left and right corners of a text field. They act as controls when users tap them (frequently they are buttons) and act on the current contents of the text field. Searching and bookmarking are two common tasks for overlay views, but others are possible. This overlay view loads a web browser using the (partial) URL in the text field:

To implement an overlay view, create a view of a size that fits within the height of the text field and give the view an appropriately sized image. If the view is a button or other control, specify a target object, an action selector, and the triggering control events. Usually you want an overlay view to appear when its text field is the focus of editing, so assign it to the text fields leftView or rightView property in the delegates textFieldDidBeginEditing: method. You can control when an overlay view appears during the editing sessionfor example, before the user begins entering text or only after the user begins entering textby assigning a UITextFieldViewMode constant to the leftViewMode or rightViewMode property. Listing 3-10 illustrates how you might implement an overlay view.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

31

Managing Text Fields and Text Views Using Overlay Views in Text Fields

Listing 3-10 Displaying an overlay view in a text field


- (void)textFieldDidBeginEditing:(UITextField *)textField { if (textField.tag == NameField && self.overlayButton) { textField.leftView = self.overlayButton; textField.leftViewMode = UITextFieldViewModeAlways; } }

@dynamic overlayButton;

- (UIButton *)overlayButton { if (!overlayButton) { overlayButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; UIImage *overlayImage = [UIImage imageNamed:@"bookmark.png"]; if (overlayImage) { [overlayButton setImage:overlayImage forState:UIControlStateNormal]; [overlayButton addTarget:self action:@selector(bookmarkTapped:) forControlEvents:UIControlEventTouchUpInside]; } } return overlayButton; }

If you use a control for an overlay view, be sure to implement the action method. To remove an overlay view, simply set the leftView or rightView property to nil in the textFieldDidEndEditing: delegation method, as in Listing 3-11.
Listing 3-11 Removing the overlay view
- (void)textFieldDidEndEditing:(UITextField *)textField {

if (textField.tag == NameFieldTag) { textField.leftView = nil; } // remainder of implementation....

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

32

Managing Text Fields and Text Views Tracking the Selection in Text Views

Tracking the Selection in Text Views


The textViewDidChangeSelection: method of UITextViewDelegate lets you track changes to the selections that a user makes in a text view. You can implement the method to obtain the selected substring and do something with it. Listing 3-12 is a whimsical example that makes all characters in the selected substring uppercase.
Listing 3-12 Getting the selected substring and changing it
- (void)textViewDidChangeSelection:(UITextView *)textView { NSRange r = textView.selectedRange; if (r.length == 0) { return; } NSString *selText = [textView.text substringWithRange:r]; NSString *upString = [selText uppercaseString]; NSString *newString = [textView.text stringByReplacingCharactersInRange:r withString:upString]; textView.text = newString; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

33

Displaying Web Content

If your user interface includes a UIWebView object, you can display local content or content that is loaded from the network.

Loading Local Content


When loading local content, you can either create the content dynamically or load it from a file and display it using the loadData:MIMEType:textEncodingName:baseURL: or loadHTMLString:baseURL: method. The method in Listing 4-1 uses the loadData:MIMEType:textEncodingName:baseURL: method to load the contents of a PDF file into a web view.
Listing 4-1 Loading a local PDF file into the web view

- (void)viewDidLoad { [super viewDidLoad];

NSString *thePath = [[NSBundle mainBundle] pathForResource:@"iPhone_User_Guide" ofType:@"pdf"]; if (thePath) { NSData *pdfData = [NSData dataWithContentsOfFile:thePath]; [(UIWebView *)self.view loadData:pdfData MIMEType:@"application/pdf" textEncodingName:@"utf-8" baseURL:nil]; } }

The text encoding string has no effect on PDF data but is retained in the listing for example purposes.

Loading Content From the Network


To load content from the network, you create an NSURLRequest object and pass it to the loadRequest: method of your web view.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

34

Displaying Web Content Loading Content From the Network

[self.myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"]]];

Because loading a web resource might take some time, you might display an activity indicator to indicate that the load is underway. You can do this by assigning a delegate to the web view and implementing the UIWebViewDelegate methods, as in Listing 4-2. The delegate displays an activity indicator when the load starts and hides it when the load ends. If there is a problem with the load, it creates an HTML error message and, using the loadHTMLString:baseURL: method, loads it into the web view for display.
Listing 4-2 The web-view delegate managing network loading

- (void)webViewDidStartLoad:(UIWebView *)webView { // starting the load, show the activity indicator in the status bar [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; }

- (void)webViewDidFinishLoad:(UIWebView *)webView { // finished loading, hide the activity indicator in the status bar [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; }

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { // load error, hide the activity indicator in the status bar [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

// report the error inside the webview NSString* errorString = [NSString stringWithFormat: @"<html><center><font size=+5 color='red'> An error occurred:<br>%@</font></center></html>", error.localizedDescription]; [self.myWebView loadHTMLString:errorString baseURL:nil]; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

35

Displaying Web Content Loading Content From the Network

If, after initiating a network-based load request, you must release your web view for any reason, you must cancel the pending request before releasing the web view. You can cancel a load request using the web views stopLoading method. A typical place to include this code would be in the viewWillDisappear: method of the owning view controller. To determine if a request is still pending, you can check the value in the web views loading property. Listing 4-3 illustrates how you might do this.
Listing 4-3 Stopping a load request when the web view is to disappear

- (void)viewWillDisappear:(BOOL)animated { if ( [self.myWebView loading] ) { [self.myWebView stopLoading]; } self.myWebView.delegate = nil; is hidden // disconnect the delegate as the webview

[UIApplication sharedApplication].networkActivityIndicatorVisible = NO; }

The loadRequest: example is taken from the UICatalog sample code project.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

36

Managing the Keyboard

When users touch a text field, a text view, or a field in a web view, the system displays a keyboard. You can configure the type of keyboard that is displayed along with several attributes of the keyboard. You also have to manage the keyboard when the editing session begins and ends. Because the keyboard could hide the portion of your view that is the focus of editing, this management might include adjusting the user interface to raise the area of focus so that is visible above the keyboard.

Keyboards and Input Methods


Whenever the user taps in an object capable of accepting text input, the object asks the system to display an appropriate keyboard. Depending on the needs of your program and the users preferred language, the system might display one of several different keyboards. Although your app cannot control the users preferred language (and thus the keyboards input method), it can control attributes of the keyboard that indicate its intended use, such as the configuration of any special keys and its behaviors.

Configuring the Keyboard for Text Objects


You configure the attributes of the keyboard directly through the text objects of your app. The UITextField and UITextView classes both conform to the UITextInputTraits protocol, which defines the properties for configuring the keyboard. Setting these properties programmatically or in the Interface Builder inspector window causes the system to display the keyboard of the designated type. The default keyboard configuration is designed for general text input. Figure 5-1 displays the default keyboard along with several other keyboard configurations. The default keyboard displays an alphabetical keyboard initially but the user can toggle it and display numbers and punctuation as well. Most of the other keyboards

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

37

Managing the Keyboard Keyboards and Input Methods

offer similar features as the default keyboard but provide additional buttons that are specially suited to particular tasks. However, the phone and numerical keyboards offer a dramatically different layout that is tailored towards numerical input.
Figure 5-1 Several different keyboard types

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

38

Managing the Keyboard Keyboards and Input Methods

To implement the language preferences of different users, iOS also supports different input methods and keyboard layouts for different languages, some of which are shown in Figure 5-2. The input method and layout for the keyboard is determined by the users language preferences. Input for some of these keyboards takes place in keyboard_input.eps multiple stages.
Figure
Text, Web, and Editing Programming Guide for iOS Apple, Inc. 5-2 Several different keyboards and input methods keyboard_input.tif reduced to 20%

Configuring the Keyboard for Web Views


Although the UIWebView class does not support the UITextInputTraits protocol directly, you can configure some keyboard attributes for text input elements. For example, you can include autocorrect and auto-capitalization attributes in the definition of an input element to specify the keyboards behaviors, as shown in the following example.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

39

Managing the Keyboard Managing the Keyboard

<input type="text" size="30" autocorrect="off" autocapitalization="on">

You can also control which type of keyboard is displayed when a user touches a text field in a web page. To display a telephone keypad, an email keyboard, or a URL keyboard, use the tel, email, or url keywords for the type attribute on an input element, respectively. To display a numeric keyboard, set the value of the pattern attribute to "[0-9]*" or "\d*". These keywords and the pattern attribute are part of HTML 5 and are available in iOS. The following list shows how to display each type of keyboard, including the standard keyboard. Text: <input type="text"></input> Telephone: <input type="tel"></input> URL: <input type="url"></input> Email: <input type="email"></input> Zip code: <input type="text" pattern="[0-9]*"></input>

Managing the Keyboard


Although many UIKit objects display the keyboard automatically in response to user interactions, your app still has some responsibilities for configuring and managing the keyboard. The following sections describe those responsibilities.

Receiving Keyboard Notifications


When the keyboard is shown or hidden, iOS sends out the following notifications to any registered observers:

UIKeyboardWillShowNotification UIKeyboardDidShowNotification UIKeyboardWillHideNotification UIKeyboardDidHideNotification

Each keyboard notification includes information about the size and position of the keyboard on the screen. You can access this information from the userInfo dictionary of each notification using the UIKeyboardFrameBeginUserInfoKey and UIKeyboardFrameEndUserInfoKey keys; the former gives the beginning keyboard frame, the latter the ending keyboard frame (both in screen coordinates). You should always use the information in these notifications as opposed to assuming the keyboard is a particular size or

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

40

Managing the Keyboard Managing the Keyboard

in a particular location. The size of the keyboard is not guaranteed to be the same from one input method to another and may also change between different releases of iOS. In addition, even for a single language and system release, the keyboard dimensions can vary depending on the orientation of your app. For example, Figure 5-3 shows the relative sizes of the URL keyboard in both the portrait and landscape modes. Using the information inside the keyboard notifications ensures that you always have the correct size and position information.
Figure 5-3 Relative keyboard sizes in portrait and landscape modes

Note: The rectangle contained in the UIKeyboardFrameBeginUserInfoKey and UIKeyboardFrameEndUserInfoKey properties of the userInfo dictionary should be used only for the size information it contains. Do not use the origin of the rectangle (which is always {0.0, 0.0}) in rectangle-intersection operations. Because the keyboard is animated into position, the actual bounding rectangle of the keyboard changes over time.

One reason to use keyboard notifications is so that you can reposition content that is obscured by the keyboard when it is visible. For information on how to handle this scenario, see Moving Content That Is Located Under the Keyboard (page 42). There is no defined relationship between the timing of keyboard notifications and the timing of view-controller transitions.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

41

Managing the Keyboard Managing the Keyboard

Displaying the Keyboard


When the user taps a view, the system automatically designates that view as the first responder. When this happens to a view that contains editable text, the view initiates an editing session for that text. At the beginning of that editing session, the view asks the system to display the keyboard, if it is not already visible. If the keyboard is already visible, the change in first responder causes text input from the keyboard to be redirected to the newly tapped view. Because the keyboard is displayed automatically when a view becomes the first responder, you often do not need to do anything to display it. However, you can programmatically display the keyboard for an editable text view by calling that views becomeFirstResponder method. Calling this method makes the target view the first responder and begins the editing process just as if the user had tapped on the view. If your app manages several text-based views on a single screen, it is a good idea to track which view is currently the first responder so that you can dismiss the keyboard later.

Dismissing the Keyboard


Although it typically displays the keyboard automatically, the system does not dismiss the keyboard automatically. Instead, it is your apps responsibility to dismiss the keyboard at the appropriate time. Typically, you would do this in response to a user action. For example, you might dismiss the keyboard when the user taps the Return or Done button on the keyboard or taps some other button in your apps interface. Depending on how you configured the keyboard, you might need to add some additional controls to your user interface to facilitate the keyboards dismissal. To dismiss the keyboard, you call the resignFirstResponder method of the text-based view that is currently the first responder. When a text view resigns its first responder status, it ends its current editing session, notifies its delegate of that fact, and dismisses the keyboard. In other words, if you have a variable called myTextField that points to the UITextField object that is currently the first responder, dismissing the keyboard is as simple as doing the following:
[myTextField resignFirstResponder];

Everything from that point on is handled for you automatically by the text object.

Moving Content That Is Located Under the Keyboard


When asked to display the keyboard, the system slides it in from the bottom of the screen and positions it over your apps content. Because it is placed on top of your content, it is possible for the keyboard to be placed on top of the text object that the user wanted to edit. When this happens, you must adjust your content so that the target object remains visible.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

42

Managing the Keyboard Managing the Keyboard

Adjusting your content typically involves temporarily resizing one or more views and positioning them so that the text object remains visible. The simplest way to manage text objects with the keyboard is to embed them inside a UIScrollView object (or one of its subclasses like UITableView). When the keyboard is displayed, all you have to do is reset the content area of the scroll view and scroll the desired text object into position. Thus, in response to a UIKeyboardDidShowNotification, your handler method would do the following:
1. 2. 3.

Get the size of the keyboard. Adjust the bottom content inset of your scroll view by the keyboard height. Scroll the target text field into view.

Note: The UITableViewController class automatically resizes and repositions its table view when there is in-line editing of text fields. See View Controllers and Navigation-Based Apps in Table View Programming Guide for iOS .

Figure 5-4 illustrates the preceding steps for a simple app that embeds several text fields inside a UIScrollView object. When the keyboard appears, the notification handler method adjusts the content and scroll indicator insets of the scroll view and then uses the scrollRectToVisible:animated: method of UIScrollView to scroll the tapped text field (in this case the email field) into view.
Figure 5-4 Adjusting content to accommodate the keyboard

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

43

Managing the Keyboard Managing the Keyboard

Listing 5-1 shows the code for registering to receive keyboard notifications and shows the handler methods for those notifications. This code is implemented by the view controller that manages the scroll view, and the scrollView variable is an outlet that points to the scroll view object. The keyboardWasShown: method gets the keyboard size from the info dictionary of the notification and adjusts the bottom content inset of the scroll view by the height of the keyboard. It also sets the scrollIndicatorInsets property of the scroll view to the same value so that the scrolling indicator wont be hidden by the keyboard. Note that the keyboardWillBeHidden: method doesnt use the keyboard size; it simply sets the scroll views contentInset and scrollIndicatorInsets properties to the default value, UIEdgeInsetsZero. If the active text field is hidden by the keyboard, the keyboardWasShown: method adjusts the content offset of the scroll view appropriately. The active field is stored in a custom variable (called activeField in this example) that is a member variable of the view controller and set in the textFieldDidBeginEditing: delegate method, which is itself shown in Listing 5-2 (page 45). (In this example, the view controller also acts as the delegate for each of the text fields.)
Listing 5-1 Handling the keyboard notifications

// Call this method somewhere in your view controller setup code. - (void)registerForKeyboardNotifications { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillBeHidden:) name:UIKeyboardWillHideNotification object:nil];

// Called when the UIKeyboardDidShowNotification is sent. - (void)keyboardWasShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

44

Managing the Keyboard Managing the Keyboard

scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets;

// If active text field is hidden by keyboard, scroll it so it's visible // Your app might not need or want this behavior. CGRect aRect = self.view.frame; aRect.size.height -= kbSize.height; if (!CGRectContainsPoint(aRect, activeField.frame.origin) ) { [self.scrollView scrollRectToVisible:activeField.frame animated:YES]; } }

// Called when the UIKeyboardWillHideNotification is sent - (void)keyboardWillBeHidden:(NSNotification*)aNotification { UIEdgeInsets contentInsets = UIEdgeInsetsZero; scrollView.contentInset = contentInsets; scrollView.scrollIndicatorInsets = contentInsets; }

Listing 5-2 shows some additional code used by the view controller to set and clear the activeField variable in the preceding example. During initialization, each text field in the interface sets the view controller as its delegate. Therefore, when a text field becomes active, it calls these methods. For more information on text fields and their delegate notifications, see Managing Text Fields and Text Views (page 22).
Listing 5-2 Additional methods for tracking the active text field.

- (void)textFieldDidBeginEditing:(UITextField *)textField { activeField = textField; }

- (void)textFieldDidEndEditing:(UITextField *)textField { activeField = nil; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

45

Managing the Keyboard Managing the Keyboard

There are other ways you can scroll the edited area in a scroll view above an obscuring keyboard. Instead of altering the bottom content inset of the scroll view, you can extend the height of the content view by the height of the keyboard and then scroll the edited text object into view. Although the UIScrollView class has a contentSize property that you can set for this purpose, you can also adjust the frame of the content view, as shown in Listing 5-3. This code also uses the setContentOffset:animated: method to scroll the edited field into view, in this case scrolling it just above the top of the keyboard.
Listing 5-3 Adjusting the frame of the content view and scrolling a field above the keyboard

- (void)keyboardWasShown:(NSNotification*)aNotification { NSDictionary* info = [aNotification userInfo]; CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; CGRect bkgndRect = activeField.superview.frame; bkgndRect.size.height += kbSize.height; [activeField.superview setFrame:bkgndRect]; [scrollView setContentOffset:CGPointMake(0.0, activeField.frame.origin.y-kbSize.height) animated:YES]; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

46

Copy, Cut, and Paste Operations

Users can copy text, images, or other data in one app and paste that data to another location within the same app or in a different app. You can, for example, copy a persons address in an email message and paste it into the appropriate field in the Contacts app. The UIKit framework implements copy-cut-paste in the UITextView, UITextField, and UIWebView classes. If you want this behavior in your own apps, you can either use objects of these classes or implement copy-cut-paste yourself. The following sections describe the programmatic interfaces of the UIKit that you use for copy, cut, and paste operations and explain how they are used. Note: For usage guidelines related to copy and paste operations, see Supporting Copy and Paste in iOS Human Interface Guidelines .

Copy-Paste Operations in UIKit


Several classes and an informal protocol of the UIKit framework give you the methods and mechanisms you need to implement copy, cut, and paste operations in your app:

The UIPasteboard class provides pasteboards: protected areas for sharing data within an app or between apps. The class offers methods for writing and reading items of data to and from a pasteboard. The UIMenuController class displays an edit menu above or below the selection to be copied, cut, or pasted into. The default commands of the edit menu are (potentially) Copy, Cut, Paste, Select, and Select All. You can also add custom menu items to the edit menu (see Adding Custom Items to the Edit Menu (page 62)). The UIResponder class declares the method canPerformAction:withSender:. Responder classes can implement this method to show and remove commands of the edit menu based on the current context. The UIResponderStandardEditActions informal protocol declares the interface for handling copy, cut, paste, select, and select-all commands. When users tap one of the commands in the edit menu, the corresponding UIResponderStandardEditActions method is invoked.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

47

Copy, Cut, and Paste Operations Pasteboard Concepts

Pasteboard Concepts
A pasteboard is a standardized mechanism for exchanging data within apps or between apps. The most familiar use for pasteboards is handling copy, cut, and paste operations:

When a user selects data in an app and chooses the Copy (or Cut) menu command, the selected data is placed onto a pasteboard. When the user chooses the Paste menu command (either in the same or a different app), the data on a pasteboard is copied to the current app from the pasteboard.

In iOS, a pasteboard is also used to support Find operations. Additionally, you may use pasteboards to transfer data between apps using custom URL schemes instead of copy, cut, and paste commands; see Updating Your Info.plist Settings in iOS App Programming Guide for information about this technique. Regardless of the operation, the basic tasks you perform with a pasteboard object are to write data to a pasteboard and to read data from a pasteboard. Although these tasks are conceptually simple, they mask a number of important details. The main complexity is that there may be a number of ways to represent data, and this complexity leads to considerations of efficiency. These and other issues are discussed in the following sections.

Named Pasteboards
Pasteboards may be public or private. Public pasteboards are called system pasteboards; private pasteboards are created by apps, and hence are called app pasteboards. Pasteboards must have unique names. UIPasteboard defines two system pasteboards, each with its own name and purpose:

UIPasteboardNameGeneral is for cut, copy, and paste operations involving a wide range of data types.

You can obtain a singleton object representing the General pasteboard by invoking the generalPasteboard class method.

UIPasteboardNameFind is for search operations. The string currently typed by the user in the search

bar (UISearchBar) is written to this pasteboard, and thus can be shared between apps. You can obtain an object representing the Find pasteboard by calling the pasteboardWithName:create: class method, passing in UIPasteboardNameFind for the name. Typically you use one of the system-defined pasteboards, but if necessary you can create your own app pasteboard using pasteboardWithName:create: If you invoke pasteboardWithUniqueName, UIPasteboard gives you a uniquely-named app pasteboard. You can discover the name of a pasteboard through its name property.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

48

Copy, Cut, and Paste Operations Pasteboard Concepts

Pasteboard Persistence
Pasteboards can be persistent. When a pasteboard is persistent, it continues to exist past app terminations and across system reboots. System pasteboards are persistent. Although app pasteboards by default are not persistent, an app can mark them as persistent by setting the persistent property to YES. App pasteboards that are not persistent only last until the owning (creating) app quits. A persistent app pasteboard is removed when the app that created it is uninstalled.

Pasteboard Owner and Items


The object that last put data onto the pasteboard is referred to as the pasteboard owner. Each piece of data placed onto a pasteboard is considered a pasteboard item. The pasteboard can hold single or multiple items. Apps can place or retrieve as many items as they wish. For example, say a user selection in a view contains both text and an image. The pasteboard lets you copy the text and the image to the pasteboard as separate items. An app reading multiple items from a pasteboard can choose to take only those items that it supports (the text, but not the image, for example). Important: When an app writes data to a pasteboard, even if it is just a single item, that data replaces the current contents of the pasteboard. Although you may use the addItems: method of UIPasteboard to append items, the write methods of the class do not append items to the current contents of the pasteboard.

Representations and UTIs


Pasteboard operations are often carried out between two different apps. Neither app is required to know about the other, including the kinds of data it can handle. To maximize the potential for sharing, a pasteboard can hold multiple representations of the same pasteboard item. For example, a rich text editor might provide HTML, PDF, and plain-text representations of the copied data. An item on a pasteboard includes all representations of that data item that the app can provide. Each representation of a pasteboard item is typically identified by a Unique Type Identifier (UTI). (A UTI is simply a string that uniquely identifies a particular data type.) The UTI provides a common means to identify data types. If you have a custom data type you wish to support, you must create a unique identifier for it. For this, you could use reverse-DNS notation for your representation-type string to ensure uniqueness; for example, a custom representation type could be com.myCompany.myApp.myType. For more information on UTIs, see Uniform Type Identifiers Overview .

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

49

Copy, Cut, and Paste Operations Pasteboard Concepts

For example, suppose an app supported selection of rich text and images. It may want to place on a pasteboard both rich text and Unicode versions of a text selection and different representations of an image selection. Each representation of each item is stored with its own data, as shown in Figure 6-1.
Figure 6-1 Pasteboard items and representations

In general, to maximize the potential for sharing, pasteboard items should include as many different representations as possible. A pasteboard reader must find the data type that best suits its capabilities (if any). Typically, this means selecting the richest type available. For example, a text editor might provide HTML (rich text) and plain-text representations of copied text data. An app that supports rich text should retrieve the HTML representation and an app that only supports plain text should retrieve the plain-text version.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

50

Copy, Cut, and Paste Operations First Steps: Identify the Selection and Display the Edit Menu

Change Count
The change count is a per-pasteboard variable that increments every time the contents of the pasteboard changesspecifically, when items are added, modified, or removed. By examining the change count (through the changeCount property), an app can determine whether the current data in the pasteboard is the same as the data it last received. Every time the change count is incremented, the pasteboard sends a notification to interested observers.

First Steps: Identify the Selection and Display the Edit Menu
If you are going to copy, cut, or paste something, you first must select it. (A paste operation often operates on an empty selection such a caret, indicating a position within a collection of items.) After selecting an itemand visually indicating the selectionyou should display the edit menu. The edit menu is a system menu that can potentially have the following commands in it: Copy, Cut, Paste, Select, and Select All. The edit menu points at the selection. When the user taps a menu item, the appropriate UIResponderStandardEditActions method implementation (such as cut: or paste:) is invoked. For more about selections and to learn how to display and manage the edit menu, see Managing the Selection and the Edit Menu (page 59).

Copying and Cutting the Selection


When users tap the Copy or Cut command of the edit menu, the system invokes the copy: or cut: method (respectively) of the responder object that implements it. Usually the first responderyour custom viewimplements these methods, but if the first responder doesnt implement them, the message travels up the responder chain in the usual fashion. Note that the UIResponderStandardEditActions informal protocol declares these methods. Note: Because UIResponderStandardEditActions is an informal protocol, any class in your app can implement its methods. But to take advantage of the default behavior for traversing the responder chain, the class implementing the methods should inherit from UIResponder and should be installed in the responder chain.

In response to a copy: or cut: message, you write the object or data represented by the selection to the pasteboard in as many different representations as you can. This operation involves the following steps (which assume a single pasteboard item):
1.

From the selection, identify or obtain the object or the binary data corresponding to the object.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

51

Copy, Cut, and Paste Operations Copying and Cutting the Selection

Binary data must be encapsulated in an NSData object. If youre going to write another type of object to the pasteboard, it must be a property-list objectthat is, an object of one of the following classes: NSString, NSArray, NSDictionary, NSDate, NSNumber, or NSURL. (For more on property-list objects, see Property List Programming Guide .)
2.

If possible, generate one or more other representations of the object or data. For example, if in the previous step you created a UIImage object representing a selected image, you could use the UIImageJPEGRepresentation and UIImagePNGRepresentation functions to convert the image to a different representation.

3.

Obtain a pasteboard object. In many cases, this is the general pasteboard, which you can get through the generalPasteboard class method.

4.

Assign a suitable UTI for each representation of data written to the pasteboard item. See Pasteboard Concepts (page 48) for a discussion of this subject.

5.

Write the data to the first pasteboard item for each representation type:

To write a data object, send a setData:forPasteboardType: message to the pasteboard object. To write a property-list object, send a setValue:forPasteboardType: message to the pasteboard object.

6.

If the command is Cut (cut: method), remove the object represented by the selection from the apps data model and update your view.

Listing 6-1 shows implementations of the copy: and cut: methods. The cut: method invokes the copy: method and then removes the selected object from the view and the data model. Note that the copy: method archives a custom object to obtain an NSData object that it can pass to the pasteboard in setData:forPasteboardType:.
Listing 6-1 Copying and cutting operations

- (void)copy:(id)sender { UIPasteboard *gpBoard = [UIPasteboard generalPasteboard]; ColorTile *theTile = [self colorTileForOrigin:currentSelection]; if (theTile) { NSData *tileData = [NSKeyedArchiver archivedDataWithRootObject:theTile]; if (tileData) [gpBoard setData:tileData forPasteboardType:ColorTileUTI]; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

52

Copy, Cut, and Paste Operations Pasting the Selection

- (void)cut:(id)sender { [self copy:sender]; ColorTile *theTile = [self colorTileForOrigin:currentSelection];

if (theTile) { CGPoint tilePoint = theTile.tileOrigin; [tiles removeObject:theTile]; CGRect tileRect = [self rectFromOrigin:tilePoint inset:TILE_INSET]; [self setNeedsDisplayInRect:tileRect]; } }

Pasting the Selection


When users tap the Paste command of the edit menu, the system invokes the paste: method of the responder object that implements it. Usually the first responderyour custom viewimplements this method, but if the first responder doesnt implement it, the message travel up the responder in the usual fashion. The paste: method is declared by the UIResponderStandardEditActions informal protocol. In response to a paste: message, you read an object from the pasteboard in a representation that your app supports. Then you add the pasted object to the apps data model and display the new object in the view in the user-indicated location. This operation involves the following steps (which assume a single pasteboard item):
1.

Obtain a pasteboard object. In many cases, this is the general pasteboard, which you can get through the generalPasteboard class method.

2.

Verify that the first pasteboard item contains data in a representation that your app can handle by calling the containsPasteboardTypes: method or the pasteboardTypes method and then examining the returned array of types. Note that you should have already performed this step in your implementation of canPerformAction:withSender:.

3.

If the first item of the pasteboard contains data that the app can handle, call one of the following methods to read it:

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

53

Copy, Cut, and Paste Operations Ending an Operation

dataForPasteboardType: if the data to be read is encapsulated in an NSData object. valueForPasteboardType: if the data to be read is encapsulated in a property-list object (see

Copying and Cutting the Selection (page 51)).


4. 5.

Add the object to the apps data model. Display a representation of the object in the user interface at the location specified by the user.

Listing 6-2 is an example of an implementation of the paste: method. It does the reverse of the combined cut: and copy: methods. The custom view first sees whether the general pasteboard holds its custom representation of data; if it does, it then reads the data from the pasteboard, adds it to the apps data model, and marks part of itselfthe current selectionfor redrawing.
Listing 6-2 Pasting data to a selection

- (void)paste:(id)sender { UIPasteboard *gpBoard = [UIPasteboard generalPasteboard]; NSArray *pbType = [NSArray arrayWithObject:ColorTileUTI]; ColorTile *theTile = [self colorTileForOrigin:currentSelection]; if (theTile == nil && [gpBoard containsPasteboardTypes:pbType]) { NSData *tileData = [gpBoard dataForPasteboardType:ColorTileUTI]; ColorTile *theTile = (ColorTile *)[NSKeyedUnarchiver unarchiveObjectWithData:tileData]; if (theTile) { theTile.tileOrigin = self.currentSelection; [tiles addObject:theTile]; CGRect tileRect = [self rectFromOrigin:currentSelection inset:TILE_INSET]; [self setNeedsDisplayInRect:tileRect]; } } }

Ending an Operation
When your implementation of the cut:, copy: or paste: command returns, the edit menu is automatically hidden. You can programmatically keep it visible if you want. For more information, see Dismissing the Edit Menu (page 63)

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

54

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 viewseither by loading a nib file or creating the views in codeand assign them to their properties. Custom view classes (and other

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

55

Custom Views for Data Input Input Views and Input Accessory Views

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 propertythat is, dont synthesize the properties accessor methods. In their getter-method implementations, they should return it the view, loading or creating it if it doesnt 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 youd 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 apps main bundle and call loadNibNamed:owner:options: on it, passing the name of the nib file, the Files 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; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

56

Custom Views for Data Input Playing Input Clicks

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 (page 37) 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.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

57

Custom Views for Data Input Playing Input Clicks

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 (page 57). 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 .)

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

58

Displaying and Managing the Edit Menu

The edit menu is a contextual menu that is displayed to offer commands that can be performed on a selection such as a word in a text view or an image. The edit menu is an integral part of copy, cut, and paste operations, for which it displays (potentially) the commands Copy, Cut, Paste, Select, and Select All. However, you can add custom menu items to the edit menu to perform other kinds of actions on selections.

Managing the Selection and the Edit Menu


To copy or cut something in a view, or to do anything else with it, that something must be selected. It can be a range of text, an image, a URL, a color, or any other representation of data, including custom objects. You must manage the selection of objects in that view yourself. If the user selects an object in the view by making a certain touch gesture (for example, a double-tap) you must handle that event, internally record the selection (and deselect any previous selection), and perhaps visually indicate the new selection in the view. If it is possible for users to select multiple objects in your view for copy-cut-paste operations, you must implement that multiple-selection behavior. Note: Techniques for handling touch events, including the use of gesture recognizers, are discussed in Event Handling Guide for iOS .

When your app determines that the user has requested the edit menuwhich could be the action of making a selectionyou should complete the following steps to display the menu:
1.

Call the sharedMenuController class method of UIMenuController to get the global menu-controller instance. Compute the boundaries of the selection and with the resulting rectangle call the setTargetRect:inView: method. The edit menu is displayed above or below this rectangle, depending how close the selection is to the top or bottom of the screen. Call the setMenuVisible:animated: method (with YES for both arguments) to animate the display of the edit menu above or below the selection.

2.

3.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

59

Displaying and Managing the Edit Menu Managing the Selection and the Edit Menu

Listing 8-1 illustrates how you might display the edit menu in an implementation of the touchesEnded:withEvent: method for handling copy, cut, and paste operations. (Note that the example omits the section of code that handles the selection.) This code snippet also shows the custom view sending itself a becomeFirstResponder message to ensure that it is the first responder for the subsequent copy, cut, and paste operations.
Listing 8-1 Displaying the edit menu

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *theTouch = [touches anyObject];

if ([theTouch tapCount] == 2

&& [self becomeFirstResponder]) {

// selection management code goes here...

// bring up edit menu. UIMenuController *theMenu = [UIMenuController sharedMenuController]; CGRect selectionRect = CGRectMake (currentSelection.x, currentSelection.y, SIDE, SIDE); [theMenu setTargetRect:selectionRect inView:self]; [theMenu setMenuVisible:YES animated:YES];

} }

The menu initially includes all commands for which the first responder has corresponding UIResponderStandardEditActions method implementations (copy:, paste:, and so on). Before the menu is displayed, however, the system sends a canPerformAction:withSender: message to the first responder, which in many cases is the custom view itself. In its implementation of this method, the responder evaluates whether the command (indicated by the selector in the first argument) is applicable in the current context. For example, if the selector is paste: and there is no data in the pasteboard of a type the view can handle, the responder should return NO to suppress the Paste command. If the first responder does not implement the canPerformAction:withSender: method, or does not handle the given command, the message travels up the responder chain. Listing 8-2 shows an implementation of the canPerformAction:withSender: method that looks for message matching the cut:, copy:, and paste: selectors; it enables or disables the Copy, Cut, and Paste menu commands based on the current selection context and, for paste, the contents of the pasteboard.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

60

Displaying and Managing the Edit Menu Managing the Selection and the Edit Menu

Listing 8-2

Conditionally enabling menu commands

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { BOOL retValue = NO; ColorTile *theTile = [self colorTileForOrigin:currentSelection];

if (action == @selector(paste:) ) retValue = (theTile == nil) && [[UIPasteboard generalPasteboard] containsPasteboardTypes: [NSArray arrayWithObject:ColorTileUTI]]; else if ( action == @selector(cut:) || action == @selector(copy:) ) retValue = (theTile != nil); else retValue = [super canPerformAction:action withSender:sender]; return retValue; }

Note that the final else clause in this method calls the superclass implementation to give any superclass a chance to handle commands that the subclass chooses to ignore. Note that a menu command, when acted upon, can change the context for other menu commands. For example, if the user selects all objects in the view, the Copy and Cut commands should be included in the menu. In this case the responder can, while the menu is still visible, call update on the menu controller; this results in the reinvocation of canPerformAction:withSender: on the first responder.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

61

Displaying and Managing the Edit Menu Adding Custom Items to the Edit Menu

Adding Custom Items to the Edit Menu


You can add a custom item to the edit menu. When users tap this item, a command is issued that affects the current target in an app-specific way. The UIKit framework accomplishes this through the target-action mechanism. The tap of an item results in an action message being sent to the first object in the responder chain that can handle the message. Figure 8-1 shows an example of a custom menu item (Change Color).
Figure 8-1 An edit menu with a custom menu item

An instance of the UIMenuItem class represents a custom menu item. UIMenuItem objects have two properties, a title and an action selector, which you can change at any time. To implement a custom menu item, you must initialize a UIMenuItem instance with these properties, add the instance to the menu controllers array of custom menu items, and then implement the action method for handling the command in the appropriate responder subclass. Other aspects of implementing a custom menu item are common to all code that uses the singleton UIMenuController object. In a custom or overridden view, you set the view to be the first responder, get the shared menu controller, set a target rectangle, and then display the edit menu with a call to setMenuVisible:animated:. The simple example in Listing 8-3 adds a custom menu item for changing a custom views color between red and black.
Listing 8-3 Implementing a Change Color menu item

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {} - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {} - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *theTouch = [touches anyObject]; if ([theTouch tapCount] == 2) { [self becomeFirstResponder]; UIMenuItem *menuItem = [[UIMenuItem alloc] initWithTitle:@"Change Color" action:@selector(changeColor:)];

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

62

Displaying and Managing the Edit Menu Dismissing the Edit Menu

UIMenuController *menuCont = [UIMenuController sharedMenuController]; [menuCont setTargetRect:self.frame inView:self.superview]; menuCont.arrowDirection = UIMenuControllerArrowLeft; menuCont.menuItems = [NSArray arrayWithObject:menuItem]; [menuCont setMenuVisible:YES animated:YES]; } } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {}

- (BOOL)canBecomeFirstResponder { return YES; }

- (void)changeColor:(id)sender { if ([self.viewColor isEqual:[UIColor blackColor]]) { self.viewColor = [UIColor redColor]; } else { self.viewColor = [UIColor blackColor]; } [self setNeedsDisplay]; }

Note: The arrowDirection property of UIMenuController, shown in Listing 8-3, allows you to specify the direction the arrow attached to the edit menu points at its target rectangle.

Dismissing the Edit Menu


When your implementation of a system or custom command returns, the edit menu is automatically hidden. You can keep the menu visible with the following line of code:
[UIMenuController sharedMenuController].menuVisible = YES;

The system may hide the edit menu at any time. For example, it hides the menu when an alert is displayed or the user taps in another area of the screen. If you have state or a display that depends on whether the edit menu is visible, you should listen for the notification named UIMenuControllerWillHideMenuNotification and take an appropriate action.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

63

Using Text Kit to Draw and Manage Text

The UIKit framework includes several classes whose purpose is to display text in an apps user interface: UITextView, UITextField, UILabel, and UIWebView, as described in Displaying Text Content in iOS (page 11). Text views, created from the UITextView class, are meant to display large amounts of text. Underlying UITextView is a powerful layout engine called Text Kit. If you need to customize the layout process or you need to intervene in that behavior, you can use Text Kit. For smaller amounts of text and special needs requiring custom solutions, you can use alternative, lower-level technologies, as described in Lower Level Text-Handling Technologies (page 79). Text Kit is a set of classes and protocols in the UIKit framework providing high-quality typographical services that enable apps to store, lay out, and display text with all the characteristics of fine typesetting, such as kerning, ligatures, line breaking, and justification. Text Kit is built on top of Core Text, so it provides the same speed and power. UITextView is fully integrated with Text Kit; it provides editing and display capabilities that enable users to input text, specify formatting attributes, and view the results. The other Text Kit classes provide text storage and layout capabilities. Figure 9-1 shows the position of Text Kit among other iOS text and graphics frameworks.
Figure 9-1 Text Kit Framework Position

Text Kit gives you complete control over text rendering in user interface elements. In addition to UITextView, UITextField and UILabel are built on top of Text Kit, and it seamlessly integrates with animations, UICollectionView and UITableView. Text Kit is designed with a fully extensible object-oriented architecture that supports subclassing, delegation, and a thorough set of notifications enabling deep customization.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

64

Using Text Kit to Draw and Manage Text Primary Text Kit Objects

Primary Text Kit Objects


The data flow paths among the primary Text Kit objects are shown in Figure 9-2. Text views are instances of UITextView class, text containers are instances of NSTextContainer class, the layout manager is an instance of NSLayoutManager class, and the text storage is an instance of NSTextStorage class. In Text Kit, an NSTextStorage object stores the text that is displayed by a UITextView object and laid out by an NSLayoutManager object into an area defined by NSTextContainer object.
Figure 9-2 Primary Text Kit Objects

An NSTextContainer object defines a region where text can be laid out. Typically, a text container defines a rectangular area, but by creating a subclass of NSTextContainer you can create other shapes: circles, pentagons, or irregular shapes, for example. Not only does a text container describe the outline of an area that can be filled with text, it maintains an array of Bezier paths that are exclusion zones within its area where text is not laid out. As it is laid out, text flows around the exclusion paths, providing a means to include graphics and other non-text layout elements.
NSTextStorage defines the fundamental storage mechanism of the Text Kits extended text-handling system. NSTextStorage is a subclass of NSMutableAttributedString that stores the characters and attributes

manipulated by the text system. It ensures that text and attributes are maintained in a consistent state across editing operations. In addition to storing the text, an NSTextStorage object manages a set of client NSLayoutManager objects, notifying them of any changes to its characters or attributes so that they can relay and redisplay the text as needed. An NSLayoutManager object orchestrates the operation of the other text handling objects. It intercedes in operations that convert the data in an NSTextStorage object to rendered text in a views display area. It maps Unicode character codes to glyphs and oversees the layout of the glyphs within the areas defined by NSTextContainer objects.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

65

Using Text Kit to Draw and Manage Text Text Attributes

Note: NLayoutManager, NSTextStorage, and NSTextContainer can be accessed from subthreads as long as the app guarantees the access from a single thread.

For reference information about UITextView, see UITextView Class Reference . NSTextContainer is described in NSTextContainer Class Reference for iOS , NSLayoutManager in NSLayoutManager Class Reference for iOS , and NSTextStorage in NSTextStorage Class Reference for iOS .

Text Attributes
Text Kit handles three kinds of text attributes: character attributes, paragraph attributes, and document attributes. Character attributes include traits such as font, color, and subscript, which can be associated with an individual character or a range of characters. Paragraph attributes are traits such as indentation, tabs, and line spacing. Document attributes include documentwide traits such as paper size, margins, and view zoom percentage.

Character Attributes
An attributed string stores character attributes as key-value pairs in NSDictionary objects. The key is an attribute name, represented by an identifier (an NSString constant) such as NSFontAttributeName. Figure 9-3 shows an attributed string with an attribute dictionary applied to a range within the string. ns_attributed_string.eps
Cocoa_Text_Architecture Apple, Inc.

Figure 9-3

Composition of an attributed string

Conceptually, each character in an attributed string has an associated dictionary of attributes. Typically, however, an attribute dictionary applies to a longer range of characters, a run of text. The NSAttributedString class provides methods that take a character index and return the associated attribute dictionary and the range to which its attribute values apply, such as attributesAtIndex:effectiveRange:.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

66

Using Text Kit to Draw and Manage Text Text Attributes

You can assign any attribute key-value pair you choose to a range of characters, in addition to working with predefined attributes. You add the attributes to the appropriate character range in the NSTextStorage object using the NSMutableAttributedString method addAttribute:value:range:. You can also create an NSDictionary object containing the names and values of a set of custom attributes and add them to the character range in a single step using the addAttributes:range: method. To make use of your custom attributes, you need a custom subclass of NSLayoutManager to work with them. Your subclass should override the drawGlyphsForGlyphRange:atPoint: method. Your override can first call the superclass to draw the glyph range and then draw your own attributes on top. Alternatively, your override can draw the glyphs entirely your own way.

Paragraph Attributes
Paragraph attributes affect the way the layout manager arranges lines of text into paragraphs on a page. The text system encapsulates paragraph attributes in objects of the NSParagraphStyle class. The value of one of the predefined character attributes, NSParagraphStyleAttributeName, points to an NSParagraphStyle object containing the paragraph attributes for that character range. Attribute fixing ensures that only one NSParagraphStyle object pertains to the characters throughout each paragraph. Paragraph attributes include traits such as alignment, tab stops, line-breaking mode, and line spacing (also known as leading ).

Document Attributes
Document attributes pertain to a document as a whole. Document attributes include traits such as paper size, margins, and view zoom percentage. Although the text system has no built-in mechanism to store document attributes, NSAttributedString initialization methods such as initWithRTF:documentAttributes: can populate an NSDictionary object that you provide with document attributes derived from a stream of RTF or HTML data. Conversely, methods that write RTF data, such as RTFFromRange:documentAttributes:, write document attributes if you pass a reference to an NSDictionary object containing them with the message.

Attribute Fixing
Editing attributed strings can cause inconsistencies that must be cleaned up by attribute fixing. The UIKit extensions to NSMutableAttributedString define the fixAttributesInRange: method to fix inconsistencies among attachment, character, and paragraph attributes. These methods ensure that attachments dont remain after their attachment characters are deleted, that character attributes apply only to characters available in that font, and that paragraph attributes are consistent throughout paragraphs.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

67

Using Text Kit to Draw and Manage Text Changing Text Storage Programmatically

Changing Text Storage Programmatically


An NSTextStorage object serves as the character data repository for Text Kit. The format for this data is an attributed string, which is a sequence of characters (in Unicode encoding) and associated attributes (such as font, color, and paragraph style). The classes that represent attributed strings are NSAttributedString and NSMutableAttributedString, of which NSTextStorage is a subclass. As described in Character Attributes (page 66), each character in a block of text has a dictionary of keys and values associated with it. A key names an attribute (such as NSFontAttributeName), and the associated value specifies the characteristics of that attribute (such as Helvetica 12-point). There are three stages to editing a text storage object programmatically. The first stage is to send it a beginEditing message to announce a group of changes. In the second stage, you send it some editing messages, such as replaceCharactersInRange:withString: and setAttributes:range:, to effect the changes in characters or attributes. Each time you send such a message, the text storage object invokes edited:range:changeInLength: to track the range of its characters affected since it received the beginEditing message. In the third stage, when youre done changing the text storage object, you send it an endEditing message. This causes it to sends out the delegate message textStorage:willProcessEditing:range:changeInLength: and invoke its own processEditing method, fixing attributes within the recorded range of changed characters. See Attribute Fixing (page 67) for information about attribute fixing. After fixing its attributes, the text storage object sends the delegate method textStorage:didProcessEditing:range:changeInLength:, giving the delegate an opportunity to verify and possibly change the attributes. (Although the delegate can change the text storage objects character attributes in this method, it cannot change the characters themselves without leaving the text storage in an inconsistent state.) Finally, the text storage object sends the processEditingForTextStorage:edited:range:changeInLength:invalidatedRange: message to each associated layout managerindicating the range in the text storage object that has changed, along with the nature of those changes. The layout managers in turn use this information to recalculate their glyph locations and redisplay if necessary.

Working with Font Objects


A computer font is a data file in a format such as OpenType or TrueType, containing information describing a set of glyphs, as described in Characters and Glyphs (page 15), and various supplementary information used in glyph rendering. The UIFont class provides the interface for getting and setting font information. A UIFont instance provides access to the fonts characteristics and glyphs. Text Kit combines character information with

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

68

Using Text Kit to Draw and Manage Text Working with Font Objects

font information to choose the glyphs used during text layout. You use font objects by passing them to methods that accept them as a parameter. Font objects are immutable, so it is safe to use them from multiple threads in your app. You dont create UIFont objects using the alloc and init methods; instead, you use preferredFontForTextStyle: with a text style constant or fontWithName:size:. You can also use a font descriptor to create a font with fontWithDescriptor:size:. These methods check for an existing font object with the specified characteristics, returning it if there is one. Otherwise, they look up the font data requested and create the appropriate font object.

Text Styles
Text styles, introduced in iOS 7, are semantic descriptions of the intended uses for fonts and are implemented by a mechanism known as Dynamic Type. Text styles are organized by use and represented by constants defined in UIFontDescriptor.h, as shown in Table 9-1. The actual font used for the purpose described by a text style can vary based on a number of dynamic considerations, including the users content size category preference, which is represented by the UIApplication property preferredContentSizeCategory. To acquire a font object for a given text style, you pass the corresponding constant to the UIFont method preferredFontForTextStyle:. To acquire a font descriptor for a text style, pass the constant to the UIFontDescriptor method preferredFontDescriptorWithTextStyle:. (See Font Descriptors (page 70) for more information about font descriptors.)
Table 9-1 Constant UIFontTextStyleHeadline UIFontTextStyleSubheadline UIFontTextStyleBody UIFontTextStyleFootnote UIFontTextStyleCaption1 UIFontTextStyleCaption2 Text style constants Usage

The font used for headings. The font used for subheads. The font used for body text. The font used for footnotes. The font used for standard captions. The font used for alternate captions.

Text styles bring many advantages to apps through the Dynamic Type mechanism, all of which enhance the readability of your text. Dynamic Type responds in a coordinated way to user preferences and responds to accessibility settings for enhanced legibility and oversize type. That is, when you call

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

69

Using Text Kit to Draw and Manage Text Working with Font Objects

preferredFontForTextStyle:, the specific font returned includes traits which vary according to user

preferences and context, including tracking (letter-spacing) adjustments, in addition to being tuned for the use specified by the particular text style constant. The fonts returned using text style constants are meant to be used for all text in an app other than text in user interface elements, such as buttons, bars, and labels. Naturally, you need to choose text styles that look right in your app. Its also important to observe the UIContentSizeCategoryDidChangeNotification so that you can relay out the text when the user changes the content size category. When your app receives that notification, it should send the invalidateIntrinsicContentSize message to views positioned by Auto Layout or send setNeedsLayout to user interface elements positioned manually. And it should invalidate preferred fonts or font descriptors and acquire new ones as needed.

Font Descriptors
Font descriptors, instantiated from the UIFontDescriptor class, provide a way to describe a font with a dictionary of attributes and are used to create UIFont objects. In particular, you can make a UIFont object from a font descriptor, you can get a descriptor from a UIFont object, and you can change a descriptor and use it to make a new font object. You can also use a font descriptor to specify custom fonts provided by an app. Font descriptors can be archived, which is an advantage working with text styles. You should not cache font objects specified by text styles because they are dynamictheir characteristics vary over time according to user preferences. But you can cache a font descriptor to preserve a description of a font, and then unarchive it later and use it to create a font object with the same characteristics. You can use font descriptors to query the system for available fonts that match particular attributes, and then create instances of fonts matching those attributes, such as names, traits, languages, and other features. For example, you can use a font descriptor to retrieve all the fonts matching a given font family name, using the family names defined by the CSS standard, as shown in Listing 9-1.
Listing 9-1 Font family name matching

UIFontDescriptor *helveticaNeueFamily = [UIFontDescriptor fontDescriptorWithFontAttributes: @{ UIFontDescriptorFamilyAttribute: @"Helvetica Neue" }]; NSArray *matches = [helveticaNeueFamily matchingFontDescriptorsWithMandatoryKeys: nil];

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

70

Using Text Kit to Draw and Manage Text Working with Font Objects

The matchingFontDescriptorsWithMandatoryKeys: method as shown returns an array of font descriptors for all the Helvetica Neue fonts on the system, such as HelveticaNeue, HelveticaNeue-Medium, HelveticaNeue-Light, HelveticaNeue-Thin, and so on. You can modify the fonts returned by preferredFontForTextStyle: by applying symbolic traits, such as bold, italic, expanded, and condensed. You can use font descriptors to modify particular traits, as shown in Listing 9-2.
Listing 9-2 Font trait modification

UIFontDescriptor *fontDescriptor = [UIFontDescriptor preferredFontDescriptorWithTextStyle: UIFontTextStyleBody]; UIFontDescriptor *boldFontDescriptor = [fontDescriptor fontDescriptorWithSymbolicTraits: UIFontDescriptorTraitBold]; UIFont *boldFont = [UIFont fontWithDescriptor: boldFontDescriptor size: 0.0];

This code snippet first retrieves a font descriptor for the body text style, then modifies that font descriptor to specify the bold trait, and finally uses the UIFont class method fontWithDescriptor:size: to return an actual font object for the body text style with a bold trait. Passing a size value of 0.0 with fontWithDescriptor:size: specifies that the size attribute originally returned with the font descriptor is preserved. This behavior is desired, of course, because the font size is determined by the dynamic type mechanism.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

71

Using Text Kit to Draw and Manage Text Working with Font Objects

Querying Font Metrics


UIFont defines a number of methods for accessing a fonts metrics information, when that information is

available. Properties such as ascender, capHeight, xHeight, and so on, all correspond to standard font metrics information. Figure 9-4 shows how the font metrics apply to glyph dimensions, and Table 9-2 lists property names that correlate with various metrics. See the property descriptions for more specific information.
Figure 9-4 Font metrics

Table 9-2 Font metric

Font metrics and related UIFont methods Properties xHeight ascender capHeight lineHeight descender pointSize

X-height Ascent Cap height Line height Descent Point size

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

72

Using Text Kit to Draw and Manage Text Laying Out Text

Laying Out Text


The layout manager object, instantiated from the NSLayoutManager class, is the central controlling object for text display in Text Kit. The layout manager performs the following actions:

Controls text storage and text container objects Generates glyphs from characters Computes glyph locations and stores the information Manages ranges of glyphs and characters Draws glyphs in text views when requested by the view Computes bounding box rectangles for lines of text Controls hyphenation Manipulates character attributes and glyph properties

In the model-view-controller paradigm, the layout manager is the controller. NSTextStorage, a subclass of NSMutableAttributedString, provides part of the model, holding a string of text characters with attributes such as typeface, style, color, and size. NSTextContainer can also be considered part of the model because it models the geometric layout of the page on which the text is laid out. UITextView (or another UIView object) provides the view in which the text is displayed. NSLayoutManager serves as the controller for the text system because it translates characters in the text storage object into glyphs, lays them out in lines according to the dimensions of one or more text container objects, and coordinates the text display in one or more text view objects.

The Layout Process


The layout manager performs text layout in two separate steps: glyph generation and glyph layout. The layout manager performs both layout steps lazily, that is, on an as-needed basis. Accordingly, some NSLayoutManager methods cause glyph generation to happen, while others do not, and the same is true with glyph layout. After it generates glyphs and after it calculates their layout locations, the layout manager caches the information to improve performance of subsequent invocations. The layout manager caches glyphs, attributes, and layout information. It keeps track of ranges of glyphs that have been invalidated by changes to the characters in the text storage. There are two ways in which a character range can be automatically invalidated: if it needs glyphs generated or if it needs glyphs laid out. If you prefer, you can manually invalidate either glyph or layout information. When the layout manager receives a message requiring knowledge of glyphs or layout in an invalidated range, it generates the glyphs or recalculates the layout as necessary.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

73

Using Text Kit to Draw and Manage Text Laying Out Text

Generating Line Fragment Rectangles


The layout manager lays text within an NSTextContainer object in lines of glyphs. The layout of these lines within the text container is determined by its shape and by any exclusion paths it contains. Wherever the line fragment rectangle intersects a region defined by an exclusion path, the lines in those parts must be shortened or fragmented; if theres a gap across the entire region, the lines that would overlap it have to be shifted to compensate. The layout manager proposes a rectangle for a given line and then asks the text container to adjust the rectangle to fit. The proposed rectangle usually spans the text containers bounding rectangle, but it can be narrower or wider, and it can also lie partially or completely outside the bounding rectangle. The message that the layout manager sends the text container to adjust the proposed rectangle is lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:, which returns the largest rectangle available for the proposed rectangle, based on the direction in which text is laid out. It also returns a rectangle containing any remaining space, such as the space left on the other side of a hole or gap in the text container. The layout manager makes one final adjustment when it actually fits text into the rectangle. This adjustment is a small amount fixed by the text container, called the line fragment padding, which defines the portion on each end of the line fragment rectangle left blank. Text is inset within the line fragment rectangle by this amount (the rectangle itself is unaffected). Padding allows for small-scale adjustment of the text containers region at the edges (and around any holes) and keeps text from directly abutting any other graphics displayed near the region. You can change the padding from its default value with the lineFragmentPadding property. Note that line fragment padding isnt a suitable means for expressing margins. For document margins, you should set the UITextView objects position and size within its enclosing view. And for text margins, you should set the textContainerInset property of the text view. In addition, you can set indentation values for individual paragraphs using NSMutableParagraphStyle properties such as headIndent. In addition to returning the line fragment rectangle itself, the layout manager returns a rectangle called the used rectangle. This is the portion of the line fragment rectangle that actually contains glyphs or other marks to be drawn. By convention, both rectangles include the line fragment padding and the interline space (which is calculated from the fonts line height metrics and the paragraphs line spacing parameters). However, the paragraph spacing (before and after) and any space added around the text, such as that caused by center-spaced text, are included only in the line fragment rectangle, and are not included in the used rectangle.

Specifying Exclusion Paths


The text container maintains an array of UIBezierPath objects representing the exclusion paths inside the receiver's bounding rectangle. When the layout manager sends the text container a lineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect: message

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

74

Using Text Kit to Draw and Manage Text Laying Out Text

proposing a line fragment rectangle intersecting one of the regions defined by the exclusion paths, the text container returns an adjusted line fragment rectangle excluding that region. This process is illustrated in Figure 9-6.
Figure 9-5 Line fragment fitting

Specifying Multipage and Multicolumn Layouts


In the simplest case, the Text Kit objects are configured singly, that is, one text storage object, one text container, and one layout manager, as shown in Figure 9-6. This configuration is instantiated automatically when you drag a text view from the object library in Interface Builder. The UITextView object vends the other objects and connects them together. You can also create this arrangement in code, as shown in Listing 9-3 (page 75).
Figure 9-6 Object configuration for a single text flow

You can also create this arrangement in code, as shown in Listing 9-3. This code could be in a view controller, for example, a subclass of UIViewController, that has an NSTextContainer property named textContainer.
Listing 9-3 Object creation for a single text flow

NSTextStorage* textStorage = [[NSTextStorage alloc] initWithString:string]; NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init]; [textStorage addLayoutManager:layoutManager]; self.textContainer = [[NSTextContainer alloc] initWithSize:self.view.bounds.size]; [layoutManager addTextContainer:self.textContainer];

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

75

Using Text Kit to Draw and Manage Text Laying Out Text

UITextView* textView = [[UITextView alloc] initWithFrame:self.view.bounds textContainer:self.textContainer]; [self.view addSubview:textView];

This configuration is limited by having only one text container and one text view. In such an arrangement, the text flows uninterrupted within the area defined by the text container. Page breaks, multicolumn layout, and more complex layouts cant be accommodated by this arrangement. By using multiple text containers, each with an associated text view, more complex layout arrangements are possible. For example, to support page breaks, an app can configure the text objects as shown in Figure 9-7.
Figure 9-7 Object configuration for paginated text

Each text container corresponds to a page of the document. The views displaying the text can be embedded in a custom view object that your app provides as a background for the text views. This custom view, in turn, can be embedded in a UIScrollView object to enable the user to scroll through the documents pages.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

76

Using Text Kit to Draw and Manage Text Laying Out Text

A multicolumn document can be modeled with a similar arrangement of objects, as shown in Figure 9-8.
Figure 9-8 Object configuration for multicolumn text

Instead of having one text container correspond to a single page, there are now two text containersone for each column on the page. Each text container controls a portion of the document. As the text is displayed, glyphs are first laid out in the top-left container. When there is no more room in that view, the layout manager informs its delegate that it has finished filling the container. The delegate can check to see whether theres more text that needs to be laid out and add another text container if necessary. The layout manager proceeds to lay out text in the next container, notifies the delegate when finished, and so on. Again, a custom view (depicted as a blue rectangle) provides a canvas for these text columns.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

77

Using Text Kit to Draw and Manage Text Laying Out Text

Not only can you have multiple text containers, you can also have multiple NSLayoutManager objects accessing the same text storage. Figure 9-9 illustrates an object arrangement with multiple layout managers. The effect of this arrangement is to provide multiple views of the same text. If the user alters the text in the top view, the change is immediately reflected in the bottom view (assuming the location of the change is within the bottom views bounds).
Figure 9-9 Object configuration for multiple views of the same text

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

78

Lower Level Text-Handling Technologies

Most apps can use the high-level text display classes and Text Kit for all their text handling. You might have an app, however, that requires the lower level programmatic interfaces from the Core Text, Core Graphics, and Core Animation frameworks as well as other APIs in UIKit itself.

Simple Text Drawing


In addition to the UIKit classes for displaying and editing text, iOS also includes several ways to draw text directly on the screen. The easiest and most efficient way to draw simple strings is using the UIKit additions to the NSString class, which is in a category named UIStringDrawing. These extensions include methods for drawing strings using a variety of attributes wherever you want them on the screen. There are also methods for computing the size of a rendered string before you actually draw it, which can help you lay out your app content more precisely. Important: There are some good reasons to avoid drawing text directly in favor of using the text objects of the UIKit framework. One is performance. Although, a UILabel object also draws its static text, it draws it only once whereas a text-drawing routine is typically called repeatedly. Text objects also afford more interaction; for example, they are selectable. The methods of UIStringDrawing draw strings at a given point (for single lines of text) or within a specified rectangle (for multiple lines). You can pass in attributes used in drawingfor example, font, line-break mode, and baseline adjustment. The methods of UIStringDrawing allow you to adjust the position of the rendered text precisely and blend it with the rest of your views content. They also let you compute the bounding rectangle for your text in advance based on the desired font and style attributes. You can also use the CATextLayer class of Core Animation to do simple text drawing. An object of this class stores a plain string or attributed string as its content and offers a set of attributes that affect that content, such as font, font size, text color, and truncation behavior. The advantage of CATextLayer is that (being a subclass of CALayer) its properties are inherently capable of animation. Core Animation is associated with the QuartzCore framework. Because instances of CATextLayer know how to draw themselves in the current graphics context, you dont need to issue any explicit drawing commands when using those instances.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

79

Lower Level Text-Handling Technologies Core Text

For information about the string-drawing extensions to NSString, see NSString UIKit Additions Reference . To learn more about CATextLayer, CALayer, and the other classes of Core Animation, read Core Animation Programming Guide .

Core Text
Core Text is a technology for custom text layout and font management. App developers typically have no need to use Core Text directly. Text Kit is built on top of Core Text, giving it the same advantages, such as speed and sophisticated typographic capability. In addition, Text Kit provides a great deal of infrastructure that you must build for yourself if you use Core Text. However, the Core Text API is accessible to developers who must use it directly. It is intended to be used by apps that have their own layout enginesfor example, a word processor that has its own page layout engine can use Core Text to generate the glyphs and position them relative to each other. Core Text is implemented as a framework that publishes an API similar to that of Core Foundationsimilar in that it is procedural (ANSI C) but is based on object-like opaque types. This API is integrated with both Core Foundation and Core Graphics. For example, Core Text uses Core Foundation and Core Graphics objects in many input and output parameters. Moreover, because many Core Foundation objects are toll-free bridged with their counterparts in the Foundation framework, you may use some Foundation objects in the parameters of Core Text functions. Note: If you use Core Text or Core Graphics to draw text, remember that you must apply a flip transform to the current text matrix to have text displayed in its proper orientationthat is, with the drawing origin at the upper-left corner of the strings bounding box.

Core Text has two major parts: a layout engine and font technology, each backed by its own collection of opaque types.

Core Text Layout Opaque Types


Core Text requires two objects whose opaque types are not native to it: an attributed string (CFAttributedStringRef) and a graphics path (CGPathRef). An attributed-string object encapsulates a string backing the displayed text and includes properties (or, attributes) that define stylistic aspects of the characters in the stringfor example, font and color. The graphics path defines the shape of a frame of text, which is equivalent to a paragraph.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

80

Lower Level Text-Handling Technologies Core Text

Core Text objects at runtime form a hierarchy that is reflective of the level of the text being processed (see Figure 10-1 (page 81)). At the top of this hierarchy is the framesetter object (CTFramesetterRef). With an attributed string and a graphics path as input, a framesetter generates one or more frames of text (CTFrameRef). As the text is laid out in a frame, the framesetter applies paragraph styles to it, including such attributes as alignment, tab stops, line spacing, indentation, and line-breaking mode. To generate frames, the framesetter calls a typesetter object (CTTypesetterRef). The typesetter converts the characters in the attributed string to glyphs and fits those glyphs into the lines that fill a text frame. (A glyph is a graphic shape used to represent a character.) A line in a frame is represented by a CTLine object (CTLineRef). A CTFrame object contains an array of CTLine objects. A CTLine object, in turn, contains an array of glyph runs, represented by objects of the CTRunRef type. A glyph run is a series of consecutive glyphs that have the same attributes and direction. Although a typesetter object returns CTLine objects, it composes those lines from arrays of glyph runs.
Figure 10-1 Core Text layout objects

Using functions of the CTLine opaque type, you can draw a line of text from an attributed string without having to go through the CTFramesetter object. You simply position the origin of the text on the text baseline and request the line object to draw itself.

Core Text Font Opaque Types


Fonts are essential to text processing in Core Text. The typesetter object uses fonts (along with the source attributed string) to convert glyphs from characters and then position those glyphs relative to one another. A graphics context is central to fonts in Core Text. You can use graphics-context functions to set the current font and draw glyphs; or you can create a CTLine object from an attributed string and use its functions to draw into the graphics context. The Core Text font system handles Unicode fonts natively. The font system includes objects of three opaque types: CTFont, CTFontDescriptor, and CTFontCollection:

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

81

Lower Level Text-Handling Technologies Core Graphics Text Drawing

Font objects (CTFontRef) are initialized with a point size and specific characteristics (from a transformation matrix). You can query the font object for its character-to-glyph mapping, its encoding, glyph data, and metrics such as ascent, leading, and so on. Core Text also offers an automatic font-substitution mechanism called font cascading. Font descriptor objects (CTFontDescriptorRef) are typically used to create font objects. Instead of dealing with a complex transformation matrix, they allow you to specify a dictionary of font attributes that include such properties as PostScript name, font family and style, and traits (for example, bold or italic). Font collection objects (CTFontCollectionRef) are groups of font descriptors that provide services such as font enumeration and access to global and custom font collections.

Its possible to convert UIFont objects to CTFont objects by calling CTFontCreateWithName, passing the font name and point size encapsulated by the UIFont object.

Core Graphics Text Drawing


Core Graphics (or Quartz) is the system framework that handles two-dimensional imaging at the lowest level. Text drawing is one of its capabilities. Generally, because Core Graphics is so low-level, it is recommended that you use one of the systems other technologies for drawing text. However, if circumstances require it, you can draw text with Core Graphics. You select fonts, set text attributes, and draw text using functions of the CGContext opaque type. For example, you can call CGContextSelectFont to set the font used, and then call CGContextSetFillColor to set the text color. You then set the text matrix (CGContextSetTextMatrix) and draw the text using CGContextShowGlyphsAtPoint. For more information about these functions and their use, see Quartz 2D Programming Guide and Core Graphics Framework Reference .

Foundation-Level Regular Expressions


The NSString class of the Foundation framework includes a simple programmatic interface for regular expressions. You call one of three methods that return a range, passing in a specific option constant and a regular-expression string. If there is a match, the method returns the range of the substring. The option is the NSRegularExpressionSearch constant, which is of bit-mask type NSStringCompareOptions; this constant tells the method to expect a regular-expression pattern rather than a literal string as the search value. The supported regular expression syntax is that defined by ICU (International Components for Unicode).

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

82

Lower Level Text-Handling Technologies Foundation-Level Regular Expressions

Note: In addition to the NSString regular-expression feature described here, iOS provides more complete support for regular expressions with the NSRegularExpression class. The ICU User Guide describes how to construct ICU regular expressions (http://userguide.icu-project.org/strings/regexp).

The NSString methods for regular expressions are the following:


rangeOfString:options: rangeOfString:options:range: rangeOfString:options:range:locale:

If you specify the NSRegularExpressionSearch option in these methods, the only other NSStringCompareOptions options you may specify are NSCaseInsensitiveSearch and NSAnchoredSearch. If a regular-expression search does not find a match or the regular-expression syntax is malformed, these methods return an NSRange structure with a value of {NSNotFound, 0}. Listing 10-1 gives an example of using the NSString regular-expression API.
Listing 10-1 Finding a substring using a regular expression
// finds phone number in format nnn-nnn-nnnn NSRange r; NSString *regEx = @"[0-9]{3}-[0-9]{3}-[0-9]{4}"; r = [textView.text rangeOfString:regEx options:NSRegularExpressionSearch]; if (r.location != NSNotFound) { NSLog(@"Phone number is %@", [textView.text substringWithRange:r]); } else { NSLog(@"Not found."); }

Because these methods return a single range value for the substring matching the pattern, certain regular-expression capabilities of the ICU library are either not available or have to be programmatically added. In addition, NSStringCompareOptions options such as backward search, numeric search, and diacritic-insensitive search are not available and capture groups are not supported.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

83

Lower Level Text-Handling Technologies ICU Regular-Expression Support

When testing the returned range, you should be aware of certain behavioral differences between searches based on literal strings and searches based on regular-expression patterns. Some patterns can successfully match and return an NSRange structure with a length of 0 (in which case the location field is of interest). Other patterns can successfully match against an empty string or, in those methods with a range parameter, with a zero-length search range.

ICU Regular-Expression Support


In case the NSString support for regular expressions is not sufficient for your needs, a modified version of the libraries from ICU 4.2.1 is included in iOS at the BSD (nonframework) level of the system. ICU (International Components for Unicode) is an open-source project for Unicode support and software internationalization. The installed version of ICU includes those header files necessary to support regular expressions, along with some modifications related to those interfaces, namely:
parseerr.h platform.h putil.h uconfig.h udraft.h uintrnal.h uiter.h umachine.h uregex.h urename.h ustring.h utf_old.h utf.h utf16.h utf8.h utypes.h uversion.h

You can read the ICU 4.2 API documentation and user guide at http://icu-project.org/apiref/icu4c/index.html.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

84

Lower Level Text-Handling Technologies Simple Text Input

Simple Text Input


An app that wants to display and process text is not limited to the text and web objects of the UIKit framework. It can implement custom views that are capable of anything from simple text entry to complex text processing and custom input. Through the available programming interfaces, these apps can acquire features such as custom text layout, multistage input, autocorrection, custom keyboards, and spell-checking. You can implement custom views that allow users to enter text at an insertion point and delete characters before that insertion point when they tap the Delete key. An instant-messaging app, for example, could have a view that allows users to enter their part of a conversation. You can acquire this capability for simple text entry by subclassing UIView, or any other view class that inherits from UIResponder, and adopting the UIKeyInput protocol. When an instance of your view class becomes the first responder, UIKit displays the system keyboard. UIKeyInput itself adopts the UITextInputTraits protocol, so you can set keyboard type, return-key type, and other attributes of the keyboard. Note: Only a subset of the available keyboards and languages are available to classes that adopt only the UIKeyInput protocol. For example, any multi-stage input method, such Chinese, Japanese, Korean, and Thai is excluded. If a class also adopts the UITextInput protocol, those input methods are then available.

To adopt UIKeyInput, you must implement the three methods it declares: hasText, insertText:, and deleteBackward. To do the actual drawing of the text, you may use any of the technologies summarized in this chapter. However, for simple text input, such as for a single line of text in a custom control, the UIStringDrawing and CATextLayer APIs are most appropriate. Listing 10-2 illustrates the UIKeyInput implementation of a custom view class. The textStore property in this example is an NSMutableString object that serves as the backing store of text. The implementation either appends or removes the last character in the string (depending on whether an alphanumeric key or the Delete key is pressed) and then redraws textStore.
Listing 10-2 Implementing simple text entry
- (BOOL)hasText { if (textStore.length > 0) { return YES; } return NO; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

85

Lower Level Text-Handling Technologies Communicating with the Text Input System

- (void)insertText:(NSString *)theText { [self.textStore appendString:theText]; [self setNeedsDisplay]; }

- (void)deleteBackward { NSRange theRange = NSMakeRange(self.textStore.length-1, 1); [self.textStore deleteCharactersInRange:theRange]; [self setNeedsDisplay]; }

- (void)drawRect:(CGRect)rect { CGRect rectForText = [self rectForTextWithInset:2.0]; // custom method [self.theColor set]; UIRectFrame(rect); [self.textStore drawInRect:rectForText withFont:self.theFont]; }

To actually draw the text in the view, this code uses the drawInRect:withFont: from the UIStringDrawing category on NSString.

Communicating with the Text Input System


The text input system of iOS manages the keyboard. It interprets taps as presses of specific keys in specific keyboards suitable for certain languages. It then sends the associated character to the target view for insertion. As explained in Simple Text Input (page 85), view classes must adopt the UIKeyInputprotocol to insert and delete characters at the caret (insertion point). However, the text input system does more than simple text entry. For example, it manages autocorrection and multistage input, which are all based upon the current selection and context. Multistage text input is required for ideographic languages such as Kanji (Japanese) and Hanzi (Chinese), which take input from phonetic keyboards. To acquire these features, a custom text view must communicate with the text input system by adopting the UITextInput protocol and implementing the related client-side classes and protocols.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

86

Lower Level Text-Handling Technologies Communicating with the Text Input System

The following section describes the general responsibilities of a custom text view that communicates with the text input system. A Guided Tour of a UITextInput Implementation (page 91) examines the most important classes and methods of a typical implementation of UITextInput.

Overview of the Client Side of Text Input


A class that wants to communicate with the text input system must adopt the UITextInput protocol. The class needs to inherit from UIResponder and is in most cases a custom view. Note: The responder class that adopts UITextInput does not have to be the view that draws and manages text (as is the case in the sample code analyzed in A Guided Tour of a UITextInput Implementation (page 91)). However, if it isnt the view that draws and manages text, the class that does adopt UITextInput should be able to communicate directly with the view that does. For simplicitys sake, the following discussion refers to the responder class that adopts UITextInput as the text view .

The text view must do its own text layout and font management; for this purpose, the Core Text framework is recommended. (Core Text (page 80) gives an overview of Core Text.) The class should also adopt and implement the UIKeyInput protocol and should set the necessary properties of the UITextInputTraits protocol.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

87

Lower Level Text-Handling Technologies Communicating with the Text Input System

The general architecture of the client and system sides of the text input system are diagrammed in Figure 10-2.
Figure 10-2 Paths of communication with the text input system

The text input system calls the UITextInput methods that the text view implements. Many of these methods request information about specific text positions and text ranges from the text view and pass the same information back to the class in other method calls. The reasons for these exchanges of text positions and text ranges are summarized in Tasks of a UITextInput Object (page 89). Text positions and text ranges in the text input system are represented by instances of custom classes. Text Positions and Text Ranges (page 88) discusses these objects in more detail. The text view also maintains references to a tokenizer and an input delegate. The text view calls methods declared by the UITextInputDelegate protocol to notify a system-provided input delegate about external changes in text and selection. The text input system communicates with a tokenizer object to determine the granularity of text unitsfor example, character, word, and paragraph. The tokenizer is an object that adopts the UITextInputTokenizer protocol. The text view includes a property (declared by UITextInput) that holds a reference to the tokenizer.

Text Positions and Text Ranges


The client app must create two classes whose instances represent positions and ranges of text in a text view. These classes must be subclasses of UITextPosition and UITextRange.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

88

Lower Level Text-Handling Technologies Communicating with the Text Input System

Although UITextPosition itself declares no methods or properties, it is an essential part of the information exchanged between a text document and the text input system. The text input system requires an object to represent a location in the text instead of, say, an integer or a structure. Moreover, a UITextPosition object can serve a practical purpose by representing a position in the visible text when the string backing the text has a different offset to that position. This happens when the string contains invisible formatting characters, such as with RTF and HTML documents, or embedded objects, such as an attachment. The custom UITextPosition class can account for these invisible characters when locating the string offsets of visible characters. In the simplest casea plain text document with no embedded objectsa custom UITextPosition object can encapsulate a single offset or index integer.
UITextRange declares a simple interface in which two of its properties are starting and ending custom UITextPosition objects. The third property holds a Boolean value that indicates whether the range is empty

(that is, has no length).

Tasks of a UITextInput Object


A class adopting the UITextInput protocol is required to implement most of the protocols methods and properties. With a few exceptions, these methods take custom UITextPosition or UITextRange objects as parameters or return one of these objects. At runtime the text system invokes these methods and, again in almost all cases, expects some object or value back. The text view must assign text positions to properties marking the beginning and end of the displayed text. In addition, it must also maintain the range of the currently selected text and the range of the currently marked text, if any. Marked text, which is part of multistage text input, represents provisionally inserted text the user has yet to confirm. It is styled in a distinctive way. The range of marked text always contains within it a range of selected text, which might be a range of characters or the caret. The methods implemented by a UITextInput object can be divided into distinctive tasks:

Returning and replacing text by text range. Given a range, either return the text in that range or replace that text with text provided by the text input system.
textInRange: replaceRange:withText:

Computing text ranges and text positions.Create and return a UITextRange object (or, simply, a text range) given two text positions; or create and return a UITextPosition object (or, simply, a text position) given a text position and an offset.
positionFromPosition:offset: positionFromPosition:inDirection:offset: textRangeFromPosition:toPosition:

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

89

Lower Level Text-Handling Technologies Communicating with the Text Input System

Evaluating text positions. Compare two text positions or return the offset from one text position to another.
comparePosition:toPosition: offsetFromPosition:toPosition:

Answering layout questions. Determine a text position or text range by extending in a given layout direction.
positionWithinRange:farthestInDirection: characterRangeByExtendingPosition:inDirection:

Hit-testing. Given a point, return the closest text position or text range.
closestPositionToPoint: closestPositionToPoint:withinRange: characterRangeAtPoint:

Returning rectangles for text ranges and text positions. Return the rectangle that encloses a text range or the rectangle at the text position of the caret.
firstRectForRange: caretRectForPosition:

The UITextInput object might also choose to implement one or more optional protocol methods. These enable it to return text styles (font, text color, background color) beginning at a specified text position and to reconcile visible text position and character offset (for those UITextPosition objects where these values are not the same). When changes occur in the text view due to external reasonsthat is, they aren't caused by calls from the text input systemthe UITextInput object should send textWillChange:, textDidChange:, selectionWillChange:, and selectionDidChange: messages to the input delegate (which it holds a reference to). For example, when users tap a text view and you set the range of selected text to place the insertion point under the finger, you would send selectionWillChange: before you change the selected range, and you send selectionDidChange: after you change the range.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

90

Lower Level Text-Handling Technologies Communicating with the Text Input System

Tokenizers
Tokenizers are objects that determine whether a text position is within or at the boundary of a text unit with a given granularity. When queried by the text input system, a tokenizer returns ranges of text units with a given granularity or the boundary text position for a text unit with a given granularity. Currently defined granularities are character, word, sentence, paragraph, line, and document; enum constants of the UITextGranularity type represent these granularities. Granularities of text units are always evaluated with reference to a storage or layout direction. The text input system uses the tokenizer in a variety of ways. For example, the keyboard might require the last sentences worth of context to figure out what the user is trying to type. Or, if the user is pressing the Option-left arrow key (on an external keyboard), the text system queries the tokenizer to find the information it needs to move to the previous word. A tokenizer is an instance of a class that conforms to the UITextInputTokenizer protocol. The UITextInputStringTokenizer class provides a default base implementation of the UITextInputTokenizer protocol that is suitable for all supported languages. If you require a tokenizer with an entirely new interpretation of text units of varying granularity, you should adopt UITextInputTokenizer and implement all of its methods. Otherwise you should subclass UITextInputStringTokenizer to provide app-specific information about layout directions. When you initialize a UITextInputStringTokenizer object, you supply it with the view adopting the UITextInput protocol. In turn, the UITextInput object should lazily create its tokenizer object in the getter method of the tokenizer property.

A Guided Tour of a UITextInput Implementation


SimpleTextInput is a simple text-editing app based on Core Text. It has two custom subclasses of UIView. One view subclass, SimpleCoreTextView, provides text layout and editing support using Core Text. The other view subclass, EditableCoreTextView, adopts the UIKeyInput protocol to enable text input; it also adopts the UITextInput protocol and creates and implements the related subclasses to communicate with the text input system. EditableCoreTextView embeds SimpleCoreTextView as an instance variable, instantiates it, and calls through to it in most UITextInput and UIKeyInput method implementations.

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

91

Lower Level Text-Handling Technologies Communicating with the Text Input System

Note: For reasons of space, the guided tour shows implementations of the UITextInput methods that are most important or illustrative. However, it is possible to extrapolate from these chosen implementations to the others of the protocols. The code was taken from the SimpleTextInput sample code project.

Subclasses of UITextPosition and UITextRange


EditableCoreTextView creates a custom subclass of UITextPosition called IndexedPosition and a

custom subclass of UITextRange called IndexedRange. These subclasses simply encapsulate a single index value and an NSRange value based on two of those indexes. Listing 10-3 shows the declaration of these classes.
Listing 10-3 Declaring the IndexedPosition and IndexedRange classes
@interface IndexedPosition : UITextPosition { NSUInteger _index; id <UITextInputDelegate> _inputDelegate; } @property (nonatomic) NSUInteger index; + (IndexedPosition *)positionWithIndex:(NSUInteger)index; @end

@interface IndexedRange : UITextRange { NSRange _range; } @property (nonatomic) NSRange range; + (IndexedRange *)rangeWithNSRange:(NSRange)range;

@end

Both classes declare class factory methods to vend instances. Listing 10-4 shows the implementation of these methods as well as the methods declared by the UITextRange class.
Listing 10-4 Implementing the IndexedPosition and IndexedRange classes
@implementation IndexedPosition @synthesize index = _index;

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

92

Lower Level Text-Handling Technologies Communicating with the Text Input System

+ (IndexedPosition *)positionWithIndex:(NSUInteger)index { IndexedPosition *pos = [[IndexedPosition alloc] init]; pos.index = index; return [pos autorelease]; }

@end

@implementation IndexedRange @synthesize range = _range;

+ (IndexedRange *)rangeWithNSRange:(NSRange)nsrange { if (nsrange.location == NSNotFound) return nil; IndexedRange *range = [[IndexedRange alloc] init]; range.range = nsrange; return [range autorelease]; }

- (UITextPosition *)start { return [IndexedPosition positionWithIndex:self.range.location]; }

- (UITextPosition *)end { return [IndexedPosition positionWithIndex:(self.range.location + self.range.length)]; }

-(BOOL)isEmpty { return (self.range.length == 0); } @end

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

93

Lower Level Text-Handling Technologies Communicating with the Text Input System

Inserting and Deleting Text


A text view that adopts the UITextInput protocol must also adopt the UIKeyInput protocol. That means it must implement the insertText:, deleteBackward, and hasText methods as discussed in Simple Text Input (page 85). Because the EditableCoreTextView class is adopting UITextInput, it must also maintain the selected and marked text ranges (that is, the current values of the selectedTextRange and markedTextRange properties) as text is entered and deleted. Listing 10-5 illustrates how EditableCoreTextView does this when text is entered. If there is marked text when a character is entered, it replaces the marked text with the character by calling the replaceCharactersInRange:withString: method on the backing mutable string. If there is a selected range of text, it replaces the characters in that range with the input character. Otherwise, the method inserts the input character at the caret.
Listing 10-5 Inserting text input into storage and updating selected and marked ranges
- (void)insertText:(NSString *)text { NSRange selectedNSRange = _textView.selectedTextRange; NSRange markedTextRange = _textView.markedTextRange;

if (markedTextRange.location != NSNotFound) { [_text replaceCharactersInRange:markedTextRange withString:text]; selectedNSRange.location = markedTextRange.location + text.length; selectedNSRange.length = 0; markedTextRange = NSMakeRange(NSNotFound, 0); } else if (selectedNSRange.length > 0) { [_text replaceCharactersInRange:selectedNSRange withString:text]; selectedNSRange.length = 0; selectedNSRange.location += text.length; } else { [_text insertString:text atIndex:selectedNSRange.location]; selectedNSRange.location += text.length; } _textView.text = _text; _textView.markedTextRange = markedTextRange; _textView.selectedTextRange = selectedNSRange; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

94

Lower Level Text-Handling Technologies Communicating with the Text Input System

Even though the structure of the deleteBackward method implemented by EditableCoreTextView is identical to the insertText: method, there are appropriate differences in how the selected and marked text ranges are adjusted. Another difference is that the deleteCharactersInRange: method is called on the backing mutable string rather than replaceCharactersInRange:withString:.

Returning and Replacing Text by Range


Any text view that communicates with the text input system must, when requested, return a specified range of text and replace a range of text with a given string. The classes in our example, EditableCoreTextView and SimpleCoreTextView, maintain synchronized copies of the backing string object (EditableCoreTextView as a NSMutableString object). The implementations of textInRange: and replaceRange:withText: in Listing 10-6 call the appropriate NSString methods on the backing string to accomplish their essential functions.
Listing 10-6 Implementations of textInRange: and replaceRange:withText:
- (NSString *)textInRange:(UITextRange *)range { IndexedRange *r = (IndexedRange *)range; return ([_text substringWithRange:r.range]); }

- (void)replaceRange:(UITextRange *)range withText:(NSString *)text { IndexedRange *r = (IndexedRange *)range; NSRange selectedNSRange = _textView.selectedTextRange; if ((r.range.location + r.range.length) <= selectedNSRange.location) { selectedNSRange.location -= (r.range.length - text.length); } else { // Need to also deal with overlapping ranges. } [_text replaceCharactersInRange:r.range withString:text]; _textView.text = _text; _textView.selectedTextRange = selectedNSRange; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

95

Lower Level Text-Handling Technologies Communicating with the Text Input System

When the text property of SimpleCoreTextView changes (as shown in the implementation of replaceRange:withText:), SimpleCoreTextView lays out the text again and redraws it using Core Text functions.

Maintaining Selected and Marked Text Ranges


Because editing operations are performed on selected and marked text, the text input system frequently requests that the text view return and set the ranges of selected and marked text. Listing 10-7 shows how EditableCoreTextView returns the ranges of selected and marked text by implementing getter methods for the selectedTextRange and markedTextRangeproperties.
Listing 10-7 Returning ranges of selected and marked text
- (UITextRange *)selectedTextRange { return [IndexedRange rangeWithNSRange:_textView.selectedTextRange]; }

- (UITextRange *)markedTextRange { return [IndexedRange rangeWithNSRange:_textView.markedTextRange]; }

The setter method for the selectedTextRange in Listing 10-8 simply sets the selected-text range on the embedded text view. The setMarkedText:selectedRange: method is more complex because, as you may recall, the range of marked text contains within it the range of selected text (even if the range merely identifies the caret), and these ranges have to be reconciled to reflect the situation after the insertion of text.
Listing 10-8 Setting the range of selected text and setting the marked text
- (void)setSelectedTextRange:(UITextRange *)range { IndexedRange *r = (IndexedRange *)range; _textView.selectedTextRange = r.range; }

- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange { NSRange selectedNSRange = _textView.selectedTextRange; NSRange markedTextRange = _textView.markedTextRange;

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

96

Lower Level Text-Handling Technologies Communicating with the Text Input System

if (markedTextRange.location != NSNotFound) { if (!markedText) markedText = @""; [_text replaceCharactersInRange:markedTextRange withString:markedText]; markedTextRange.length = markedText.length; } else if (selectedNSRange.length > 0) { [_text replaceCharactersInRange:selectedNSRange withString:markedText]; markedTextRange.location = selectedNSRange.location; markedTextRange.length = markedText.length; } else { [_text insertString:markedText atIndex:selectedNSRange.location]; markedTextRange.location = selectedNSRange.location; markedTextRange.length = markedText.length; } selectedNSRange = NSMakeRange(selectedRange.location + markedTextRange.location, selectedRange.length);

_textView.text = _text; _textView.markedTextRange = markedTextRange; _textView.selectedTextRange = selectedNSRange; }

Note that EditableCoreTextView replaces the text by calling the replaceCharactersInRange:withString: method on its mutable string object, which it then assigns to the text property of the embedded text view.

Frequently Called UITextInput Methods


When users type characters on the keyboard and when those characters enter text storage and are laid out, the text input system requests information from the object adopting the UITextInput protocol. Three of the more frequently called methods are textRangeFromPosition:toPosition:, offsetFromPosition:toPosition:, and positionFromPosition:offset:. The text input system calls positionFromPosition:offset: to get the position in the text thats a given offset from another position. Listing 10-9 shows how EditableCoreTextView implements this method (which includes range checking).

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

97

Lower Level Text-Handling Technologies Communicating with the Text Input System

Listing 10-9 Implementing positionFromPosition:offset:


- (UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset { IndexedPosition *pos = (IndexedPosition *)position; NSInteger end = pos.index + offset; if (end > _text.length || end < 0) return nil; return [IndexedPosition positionWithIndex:end]; }

The offsetFromPosition:toPosition: method should satisfy the opposite request and return a value specifying the offset between two text positions. EditableCoreTextView implements it as shown in Listing 10-10.
Listing 10-10 Implementing offsetFromPosition:toPosition:

- (NSInteger)offsetFromPosition:(UITextPosition *)from toPosition:(UITextPosition *)toPosition { IndexedPosition *f = (IndexedPosition *)from; IndexedPosition *t = (IndexedPosition *)toPosition; return (t.index - f.index); }

Finally, the text input system frequently asks a text view for a text range that falls between two text positions. Listing 10-11 shows an implementation of textRangeFromPosition:toPosition: that returns this range.
Listing 10-11 Implementing textRangeFromPosition:toPosition:

- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition { IndexedPosition *from = (IndexedPosition *)fromPosition; IndexedPosition *to = (IndexedPosition *)toPosition; NSRange range = NSMakeRange(MIN(from.index, to.index), ABS(to.index from.index)); return [IndexedRange rangeWithNSRange:range]; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

98

Lower Level Text-Handling Technologies Communicating with the Text Input System

Returning Rectangles
When a correction bubble appears and when the user types in Japanese, the text input system sends firstRectForRange: and caretRectForPosition: to the text view. The purpose of both of these methods is to return a rectangle enclosing either a range of text or the caret that marks the insertion point. The EditableCoreTextView class implements the first of these methods by calling a method of its embedded text view that maps the range to an enclosing rectangle (see Listing 10-12). Before returning the rectangle, it converts it to the local coordinate system.
Listing 10-12 An implementation of firstRectForRange:

- (CGRect)firstRectForRange:(UITextRange *)range { IndexedRange *r = (IndexedRange *)range; CGRect rect = [_textView firstRectForNSRange:r.range]; return [self convertRect:rect fromView:_textView]; }

The embedded text view in this case performs the lions share of the work. Using Core Text functions, it computes the rectangle that encloses the range of text and returns it, as shown in Listing 10-13.
Listing 10-13 Mapping text range to enclosing rectangle

- (CGRect)firstRectForNSRange:(NSRange)range; { int index = range.location; NSArray *lines = (NSArray *) CTFrameGetLines(_frame); for (int i = 0; i < [lines count]; i++) { CTLineRef line = (CTLineRef) [lines objectAtIndex:i]; CFRange lineRange = CTLineGetStringRange(line); int localIndex = index - lineRange.location; if (localIndex >= 0 && localIndex < lineRange.length) { int finalIndex = MIN(lineRange.location + lineRange.length, range.location + range.length); CGFloat xStart = CTLineGetOffsetForStringIndex(line, index, NULL); CGFloat xEnd = CTLineGetOffsetForStringIndex(line, finalIndex, NULL); CGPoint origin; CTFrameGetLineOrigins(_frame, CFRangeMake(i, 0), &origin); CGFloat ascent, descent;

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

99

Lower Level Text-Handling Technologies Communicating with the Text Input System

CTLineGetTypographicBounds(line, &ascent, &descent, NULL);

return CGRectMake(xStart, origin.y - descent, xEnd - xStart, ascent + descent); } } return CGRectNull; }

For caretRectForPosition:, the approach you take would be somewhat different. Selection affinity (selectionAffinity) is a factor to consider; more importantly, keep in mind that the height and width of the caret rectangle can be different from the bounding rectangle returned from firstRectForRange:.

Hit Testing
Another area where the text input system asks the text view to map between the display of text and the storage of text is hit testing. Given a point in the text view (the text input system asks), what is the corresponding text position or text range? The UITextInput methods it calls for this information are closestPositionToPoint:, closestPositionToPoint:withinRange:, and characterRangeAtPoint:. Listing 10-14 illustrates how EditableCoreTextView implements the first of these methods.
Listing 10-14 An implementation of closestPositionToPoint:

- (UITextPosition *)closestPositionToPoint:(CGPoint)point { NSInteger index = [_textView closestIndexToPoint:point]; return [IndexedPosition positionWithIndex:(NSUInteger)index]; }

Here, as with the methods that return rectangles for text ranges or text positions, EditableCoreTextView calls a method of its embedded view that uses Core Text to calculate the character index that corresponds to the point. Listing 10-15 illustrates how the embedded view accomplishes this.
Listing 10-15 Mapping a point to a character index

- (NSInteger)closestIndexToPoint:(CGPoint)point { NSArray *lines = (NSArray *) CTFrameGetLines(_frame);

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

100

Lower Level Text-Handling Technologies Communicating with the Text Input System

CGPoint origins[lines.count]; CTFrameGetLineOrigins(_frame, CFRangeMake(0, lines.count), origins);

for (int i = 0; i < lines.count; i++) { if (point.y > origins[i].y) { CTLineRef line = (CTLineRef) [lines objectAtIndex:i]; return CTLineGetStringIndexForPosition(line, point); } } return } _text.length;

Informing the Text Input Delegate of Changes


When there is a change in text or a change in selection that is not initiated by the text input system, you should inform the text input delegate by sending it an appropriate will-change method. After making the change, send the delegate the corresponding did-change method. The text input delegate is a system-provided object that adopts the UITextInputDelegate protocol. If the class adopting the UITextInput protocol defines an inputDelegate property, the text input system automatically assigns a delegate object to this property at runtime. Listing 10-16 shows an action method that is invoked when the user taps in the text view. If the view is tapped but it isnt the first responder, the text view makes itself the first responder and starts an editing session. If the view is subsequently tapped, the text view sends a selectionWillChange: message to the text input delegate. It then clears any marked text range and resets the selected text range so that the caret is at the point in the text where the tapped occurred. After this, it calls selectionDidChange:.
Listing 10-16 Sending messages to the text input delegate

- (void)tap:(UITapGestureRecognizer *)tap { if (![self isFirstResponder]) { _textView.editing = YES; [self becomeFirstResponder]; } else { [self.inputDelegate selectionWillChange:self];

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

101

Lower Level Text-Handling Technologies Spell Checking and Word Completion

NSInteger index = [_textView closestIndexToPoint:[tap locationInView:_textView]]; _textView.markedTextRange = NSMakeRange(NSNotFound, 0); _textView.selectedTextRange = NSMakeRange(index, 0);

[self.inputDelegate selectionDidChange:self]; } }

Spell Checking and Word Completion


With an instance of the UITextChecker class, you can check the spelling of a document or offer suggestions for completing partially entered words. When spell-checking a document, a UITextChecker object searches a document at a specified offset. When it detects a misspelled word, it can also return an array of possible correct spellings, ranked in the order which they should be presented to the user (that is, the most likely replacement word comes first). You typically use a single instance of UITextChecker per document, although you can use a single instance to spell-check related pieces of text if you want to share ignored words and other state. Note: The UITextChecker class is intended for spell-checking and not for autocorrection. Autocorrection is a feature your text document can acquire by adopting the protocols and implementing the subclasses described in Communicating with the Text Input System (page 86).

The method you use for checking a document for misspelled words is
rangeOfMisspelledWordInString:range:startingAt:wrap:language:; the method used for obtaining

the list of possible replacement words is guessesForWordRange:inString:language:. You call these methods in the given order. To check an entire document, you call the two methods in a loop, resetting the starting offset to the character following the corrected word at each cycle through the loop, as shown in Listing 10-17.
Listing 10-17 Spell-checking a document

- (IBAction)spellCheckDocument:(id)sender { NSInteger currentOffset = 0; NSRange currentRange = NSMakeRange(0, 0);

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

102

Lower Level Text-Handling Technologies Spell Checking and Word Completion

NSString *theText = textView.text; NSRange stringRange = NSMakeRange(0, theText.length-1); NSArray *guesses; BOOL done = NO;

NSString *theLanguage = [[UITextChecker availableLanguages] objectAtIndex:0]; if (!theLanguage) theLanguage = @"en_US";

while (!done) { currentRange = [textChecker rangeOfMisspelledWordInString:theText range:stringRange startingAt:currentOffset wrap:NO language:theLanguage]; if (currentRange.location == NSNotFound) { done = YES; continue; } guesses = [textChecker guessesForWordRange:currentRange inString:theText language:theLanguage]; NSLog(@"---------------------------------------------"); NSLog(@"Word misspelled is %@", [theText substringWithRange:currentRange]); NSLog(@"Possible replacements are %@", guesses); NSLog(@" "); currentOffset = currentOffset + (currentRange.length-1); } }

The UITextChecker class includes methods for telling the text checker to ignore or learn words. Instead of just logging the misspelled words and their possible replacements, as the method in Listing 10-17 does, you should display some user interface that allows users to select correct spellings, tell the text checker to ignore or learn a word, and proceed to the next word without making any changes. One possible approach for an iPad app would be to use a popover view that lists the guesses in a table view and includes buttons such as Replace, Learn, Ignore, and so on. You may also use UITextChecker to obtain completions for partially entered words and display the completions in a table view in a popover view. For this task, you call the completionsForPartialWordRange:inString:language: method, passing in the range in the given

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

103

Lower Level Text-Handling Technologies Spell Checking and Word Completion

string to check. This method returns an array of possible words that complete the partially entered word. Listing 10-18 shows how you might call this method and display a table view listing the completions in a popover view.
Listing 10-18 Presenting a list of word completions for the current partial string

- (IBAction)completeCurrentWord:(id)sender {

self.completionRange = [self computeCompletionRange]; // The UITextChecker object is cached in an instance variable NSArray *possibleCompletions = [textChecker completionsForPartialWordRange:self.completionRange inString:self.textStore language:@"en"];

CGSize popOverSize = CGSizeMake(150.0, 400.0); completionList = [[CompletionListController alloc] initWithStyle:UITableViewStylePlain]; completionList.resultsList = possibleCompletions; completionListPopover = [[UIPopoverController alloc] initWithContentViewController:completionList]; completionListPopover.popoverContentSize = popOverSize; completionListPopover.delegate = self; // rectForPartialWordRange: is a custom method CGRect pRect = [self rectForPartialWordRange:self.completionRange]; [completionListPopover presentPopoverFromRect:pRect inView:self permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; }

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

104

Document Revision History

This table describes the changes to Text Programming Guide for iOS .

Date 2013-10-22 2013-09-18

Notes Revised introduction figure. Fixed typos. Added material describing Text Kit and typographical concepts and made associated changes throughout. Changed name from "Text, Web, and Editing Programming Guide for iOS". Updated information on pasteboard persistence and keyboard adjustment. Also made many small corrections. Made some minor corrections. Added "Playing Input Clicks" to the "Custom Views for Data Input" chapter. Incorporates information on copy-cut-paste operations, edit menu management, and custom data-input views. Made some minor corrections and clarifications, especially with keyboard management. Title changed from "Text and Web Programming Guide for iOS".

2011-03-07

2011-01-10 2010-11-15

2010-07-07

Changed the title from "Text and Web Programming Guide for iPhone OS." First version of a document that describes the technologies and techniques for displaying and managing text and web content in iOS.

2010-05-11

2013-10-22 | Copyright 2013 Apple Inc. All Rights Reserved.

105

Apple Inc. Copyright 2013 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apples copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, iPad, iPhone, OS X, Quartz, Safari, TrueType, and Xcode are trademarks of Apple Inc., registered in the U.S. and other countries. Helvetica and Times are registered trademarks of Heidelberger Druckmaschinen AG, available from Linotype Library GmbH. Java is a registered trademark of Oracle and/or its affiliates. iOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license.
Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED AS IS, AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.

Das könnte Ihnen auch gefallen