Text programming guide for iOS

106
Text Programming Guide for iOS

description

Developer documentation by Apple

Transcript of Text programming guide for iOS

Page 1: Text programming guide for iOS

Text ProgrammingGuide for iOS

Page 2: Text programming guide for iOS

Contents

About Text Handling in iOS 8At a Glance 8

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

See Also 10

Displaying Text Content in iOS 11Use Text Objects to Display Text Content 11Use Web Views to Display Web Content 13

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

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

Displaying Web Content 34Loading Local Content 34Loading Content From the Network 34

Managing the Keyboard 37Keyboards and Input Methods 37

Configuring the Keyboard for Text Objects 37

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

2

Page 3: Text programming guide for iOS

Configuring the Keyboard for Web Views 39Managing the Keyboard 40

Receiving Keyboard Notifications 40Displaying the Keyboard 42Dismissing the Keyboard 42Moving Content That Is Located Under the Keyboard 42

Copy, Cut, and Paste Operations 47Copy-Paste Operations in UIKit 47Pasteboard Concepts 48

Named Pasteboards 48Pasteboard Persistence 49Pasteboard Owner and Items 49Representations and UTIs 49Change Count 51

First Steps: Identify the Selection and Display the Edit Menu 51Copying and Cutting the Selection 51Pasting the Selection 53Ending an Operation 54

Custom Views for Data Input 55Input Views and Input Accessory Views 55Playing Input Clicks 57

Adopting the UIInputViewAudioFeedback Protocol 57Playing Input Clicks 58

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

Using Text Kit to Draw and Manage Text 64Primary Text Kit Objects 65Text Attributes 66

Character Attributes 66Paragraph Attributes 67Document Attributes 67Attribute Fixing 67

Changing Text Storage Programmatically 68Working with Font Objects 68

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

3

Contents

Page 4: Text programming guide for iOS

Text Styles 69Font Descriptors 70Querying Font Metrics 72

Laying Out Text 73The Layout Process 73Generating Line Fragment Rectangles 74Specifying Exclusion Paths 74Specifying Multipage and Multicolumn Layouts 75

Lower Level Text-Handling Technologies 79Simple Text Drawing 79Core Text 80

Core Text Layout Opaque Types 80Core Text Font Opaque Types 81

Core Graphics Text Drawing 82Foundation-Level Regular Expressions 82ICU Regular-Expression Support 84Simple Text Input 85Communicating with the Text Input System 86

Overview of the Client Side of Text Input 87A 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.

4

Contents

Page 5: Text programming guide for iOS

Figures, Tables, and Listings

Displaying Text Content in iOS 11Figure 1-1 Text classes in the UICatalog app 12Figure 1-2 A web view 14

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

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

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

Managing the Keyboard 37Figure 5-1 Several different keyboard types 38

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

5

Page 6: Text programming guide for iOS

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

Copy, Cut, and Paste Operations 47Figure 6-1 Pasteboard items and representations 50Listing 6-1 Copying and cutting operations 52Listing 6-2 Pasting data to a selection 54

Custom Views for Data Input 55Listing 7-1 Creating an input accessory view programmatically 56

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

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

Lower Level Text-Handling Technologies 79Figure 10-1 Core Text layout objects 81Figure 10-2 Paths of communication with the text input system 88

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

6

Figures, Tables, and Listings

Page 7: Text programming guide for iOS

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

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

7

Figures, Tables, and Listings

Page 8: Text programming guide for iOS

The iOS platform gives you many ways to display text in your apps and let users edit that text. It also lets youdisplay formatted text and web content in your app’s views. The resources at your disposal range from frameworkobjects—such as text views, text fields, and web views—to text layout engines that you can use directly todraw, 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 GlanceApps in iOS have a number of powerful technologies to handle text, both for editing text and for renderinghigh-quality typographically formatted text.

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

8

About Text Handling in iOS

Page 9: Text programming guide for iOS

The UIKit Framework Provides Your App with Text and Web ObjectsYou can add ready-made text views, text fields, and labels to your app’s user interface by using instances ofthe UITextView, UITextField, and UILabel. You can add and configure them programmatically or byusing the Interface Builder editor in Xcode. You can also turn a view of your app into a miniature web browsercapable of understanding and displaying HTML, CSS, and JavaScript content. You do this using a UIWebViewobject.

Relevant Chapters: “Displaying Text Content in iOS” (page 11), “Typographical Concepts” (page15), “Managing Text Fields and Text Views” (page 22), “Displaying Web Content” (page 34)

When Users Edit Text, Your App Must Manage the KeyboardWhen a user taps a text field, text view, or form field in a web view, iOS animates a keyboard into view. An appcan control which keyboard is presented; for example, for a numeric-value field, the app should select thenumeric keypad. If the entered or edited text is obscured by the keyboard, the app should adjust the viewdisplaying the text so that the text appears above the keyboard. The delegate of a text view, text field, or webview is responsible for validating edited text and for accessing and storing edited text when the user dismissesthe keyboard.

Relevant Chapters: “Managing the Keyboard” (page 37)

Your App Can Draw and Manage Text DirectlyUnderlying the text views in UIKit is a powerful layout engine called Text Kit. If you need to customize thelayout process or you need to intervene in that behavior, you can use Text Kit. Text Kit is a set of classes andprotocols that provide high-quality typographical services which enable apps to store, lay out, and display textwith 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 smalleramounts 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 aswell as other APIs in UIKit itself.

To communicate directly with the text-input system of iOS, implement the UITextInput protocol and relatedprotocols and classes. Your app can also make use of technologies for spell checking and regular expressions.

About Text Handling in iOSAt a Glance

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

9

Page 10: Text programming guide for iOS

Relevant Chapter: “Using Text Kit to Draw and Manage Text” (page 64), “Lower Level Text-HandlingTechnologies” (page 79)

Your App Has a Range of Options for the Input and Editing of DataThe UIKit framework includes programmatic interfaces for editing the data in a view and for entering data intoan app. Custom input views can replace the system keyboard to permit input of special data; input accessoryviews are a custom view above the system keyboard (or custom input view) that enables users to affect editeddata in app-specific ways. Using UIPasteboard and related classes, an app can copy, cut, and paste datawithin different locations of itself or between itself and another app. As part of copy-cut-paste operations, theuser taps a command on an contextual edit menu; your app manages this menu and can add custom commandsto it.

Relevant Chapters:: “Copy, Cut, and Paste Operations” (page 47), “Displaying and Managing theEdit Menu” (page 59), “Custom Views for Data Input” (page 55)

See AlsoThe Core Graphics and Core Animation frameworks have some text-handling capabilities. Core Animation, forexample, offers the CATextLayer class. To learn more about these capabilities, read Quartz 2D ProgrammingGuide (Core Graphics) and Core Animation Programming Guide .

To find out more about the Core Text framework, which is apropriate for developing higher-level text-handlingframeworks, read Core Text Programming Guide and Core Text Reference Collection .

About Text Handling in iOSSee Also

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

10

Page 11: Text programming guide for iOS

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

Use Text Objects to Display Text ContentText objects display styled, formatted text in a range of fonts, styles, and sizes. The UIKit framework providesthree primary classes for displaying this text content in an app’s 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 areintended 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, andpages, 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 technologycalled Text Kit, a powerful layout engine that is both easy to use and extensible. See “Using Text Kit to Drawand 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

Page 12: Text programming guide for iOS

Figure 1-1 shows examples of the primary text objects as they appear on screen. The image on the left showsseveral different styles of text fields while the image on the right shows a single text view. The callouts displayedon 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 andcontrols 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 managethe editing session. Text views send several different notifications to the delegate to let them know whenediting begins, when it ends, and to give them a chance to override some editing actions. For example, thedelegate can decide if the current text contains a valid value and prevent the editing session from ending if itdoes not. When editing does finally end, you also use the delegate to get the resulting text value and updateyour app’s data model.

Because there are slight differences in their intended usage, the delegate methods for each text view areslightly different. A delegate that supports the UITextField class implements the methods of theUITextFieldDelegate protocol. Similarly, a delegate that supports the UITextView class implements themethods of the UITextViewDelegate protocol. In both cases, you are not required to implement any of theprotocol methods, but if you do not, the text field or view is not as useful.

Displaying Text Content in iOSUse Text Objects to Display Text Content

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

12

Page 13: Text programming guide for iOS

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

Use Web Views to Display Web ContentA web view object displays web-based content. It is an instance of the UIWebView class that enables you tointegrate what is essentially a miniature web browser into your app’s user interface. The UIWebView classmakes 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 within Safari. For example, you can double-click and pinch to zoom in and out of the page and you can scroll aroundthe page by dragging your finger.

In addition to displaying content, you can also use a web view object to gather input from the user throughthe use of web forms. Like the other text classes in UIKit, if you have an editable text field on a form in yourweb page, tapping that field brings up a keyboard so that the user can enter text. Because it is an integral partof the web experience, the web view itself manages the displaying and dismissing of the keyboard for you.

Displaying Text Content in iOSUse Web Views to Display Web Content

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

13

Page 14: Text programming guide for iOS

Figure 1-2 shows an example of a UIWebView object from the UICatalog sample app, which demonstratesmany of the views and controls available in UIKit. Because it just displays HTML content, if you want the userto 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 ofthe UIWebViewDelegate protocol. Your implementations of the delegate methods can respond to failuresor 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.

Displaying Text Content in iOSUse Web Views to Display Web Content

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

14

Page 15: Text programming guide for iOS

This chapter defines some important typographical concepts relevant to the text system. Many of the termsrepresenting these concepts are reflected in text system APIs. If you’re familiar with typography, you can skipthis chapter.

Characters and GlyphsA character is the smallest unit of written language that carries meaning. Characters can correspond to aparticular sound in the spoken form of the language, as do the letters of the roman alphabet; they can represententire words, such as Chinese ideographs; or they can represent independent concepts, such as mathematicalsymbols. 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 tothat 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 bevertical, and it can have certain optional variations in form, such as serifs. Any one of these various concreteforms of a character is called a glyph. Figure 2-1 shows different glyphs that all represent the character“uppercase A.”

Figure 2-1 Glyphs of the character A

glyph_a.epsCocoa_Text_ArchitectureApple, Inc.

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

15

Typographical Concepts

Page 16: Text programming guide for iOS

Characters and glyphs do not have a one-to-one correspondence. In some cases a character may be representedby multiple glyphs, such as an “é” which may be an “e” glyph combined with an acute accent glyph “´”. In othercases, a single glyph may represent multiple characters, as in the case of a ligature, or joined letter. Figure 2-2shows 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 changesdepending on the characters next to it. Other contextual forms include alternate glyphs for characters beginningor ending a word.

Computers store characters as numbers mapped by encoding tables to their corresponding characters. Theencoding scheme native to iOS and OS X conforms to the Unicode standard. Unicode provides a standardmethodology for assigning a unique number for every character in every modern written language in theworld, independent of the platform, program, and programming language being used. This universal standardsolves 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 formwords and break lines; how to sort text in different languages; and how to format numbers, dates, times, andother elements appropriate to different languages.

Glyphs are also represented by numeric codes called glyph codes. The glyphs used to depict characters areselected by the layout manager during composition and layout processing. The layout manager determineswhich glyphs to use and where to place them in the display, or view. The layout manager caches the glyphcodes in use and provides methods to convert between characters and glyphs and between characters andview coordinates.

Typographical ConceptsCharacters and Glyphs

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

16

Page 17: Text programming guide for iOS

Typefaces and FontsA 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 letterforms in Times are related in appearance, having consistent proportions between stems (vertical strokes) andcounters (rounded shapes in letter bodies) and other elements. When laid out in blocks of text, the shapes ina typeface work together to enhance readability.

A typestyle, or simply style, is a distinguishing visual characteristic of a typeface. For example, roman typestyleis characterized by upright letters having serifs and stems thicker than horizontal lines. In italic typestyle, theletters slant to the right and are rounded, similar to cursive or handwritten letter shapes. A typeface usuallyhas several associated typestyles.

A font is a series of glyphs depicting the characters in a consistent size, typeface, and typestyle. A font isintended for use in a specific display environment. Fonts contain glyphs for all the contextual forms, such asligatures, 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 nameof a font family (as well as the name of its typeface). Times roman and Times Italic are the names of twoindividual 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, posterfonts, and fixed pitch. The text system includes objects called font descriptors, which provide font-matchingcapability, so that you can partially describe a font by creating a font descriptor with, for example, just a familyname or weight, and you can then find all the fonts on the system that match the given trait.

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

Typographical ConceptsTypefaces and Fonts

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

17

Page 18: Text programming guide for iOS

form words that are separated by spaces. Words are laid out in lines beginning at the top left of the text viewproceeding from left to right until the text reaches the right side of the view. Text then begins a new line atthe left side of the view under the beginning of the previous line, and layout proceeds in the same manner tothe bottom of the text view.

In other languages, glyph layout can be quite different. For example, some languages lay out glyphs from rightto left or vertically instead of horizontally. It is common, especially in technical writing, to mix languages withdiffering text direction, such as English and Hebrew, in the same line. Some writing systems even alternatelayout direction in every other line (an arrangement called boustrophedonic writing). Some languages do notgroup 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 atwhich to end one line and begin the next. In the text system, you can specify line breaking at either word orglyph boundaries. In roman text, a word broken between glyphs requires insertion of a hyphen glyph at thebreakpoint.

The layout manager lays out glyphs along an invisible line called the baseline. In roman text, the baseline ishorizontal, 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 placeglyphs below or centered on the baseline. Every glyph includes an origin point that the layout manager usesto align it properly with the baseline.

Glyph designers provide a set of measurements with a font, called metrics, which describe the spacing aroundeach glyph in the font. The layout manager uses these metrics to determining glyph placement. In horizontaltext, the glyph has a metric called the advance width, which measures the distance along the baseline to theorigin point of the next glyph. Typically there is some space between the origin point and the left side of theglyph, which is called the left-side bearing. There may also be space between the right side of the glyph andthe point described by the advance width, which is called the right-side bearing. The vertical dimension ofthe glyph is provided by two metrics called the ascent and the descent. The ascent is the distance from the

Typographical ConceptsText Layout

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

18

Page 19: Text programming guide for iOS

origin (on the baseline) to the top of the tallest glyphs in the font. The descent, which is the distance belowthe baseline to the bottom of the font’s deepest descender. The rectangle enclosing the visible parts of theglyph is called the bounding rectangle or bounding box. Figure 2-4 illustrates these metrics.

Figure 2-4 Glyph metrics

glyphterms.epsCocoa_Text_ArchitectureApple, Inc.

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

Figure 2-5 Kerning

kerning.epsCocoa_Text_ArchitectureApple, Inc.

Typographical ConceptsText Layout

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

19

Page 20: Text programming guide for iOS

Type systems usually measure font metrics in units called points, which measure exactly 72 per inch in mostcomputer typesetting systems. Adding the distance of the ascent and the descent of a font provides the font’spoint size.

Space added during typesetting between lines of type is called leading, after the slugs of lead used for thatpurpose in traditional metal-type page layout. The total amount of ascent plus descent plus leading providesa font’s line height. (Leading is sometimes also called linegap . It is often specified as a ratio of a font’s pointsize 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 whohave 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 wherethe 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

Typographical ConceptsText Layout

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

20

Page 21: Text programming guide for iOS

Lines of text can also be justified; for horizontal text the lines are aligned on both right and left margin byvarying interword and interglyph spacing, as shown in Figure 2-7. The system performs alignment andjustification, if requested, after the text stream has been broken into lines and hyphens added and other glyphsubstitutions made.

Figure 2-7 Justified text

justified.epsCocoa_Text_ArchitectureApple, Inc.

Typographical ConceptsText Layout

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

21

Page 22: Text programming guide for iOS

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 bookmarkbuttons in text fields.

The delegate of a UITextField or UITextView object is responsible for most of these tasks. The delegatemust adopt the UITextFieldDelegate or UITextViewDelegate protocols and implement one or moreof 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 InterfaceBuilder.

The Sequence of Messages to the DelegateIn most cases, instances of the UITextField or UITextView classes send a sequence of similarly namedmessages to their delegates when there is a change (or impending change) in first-responder status for a giventext object. When the user taps a text object, it automatically becomes first responder; as a result, the systemdisplays the keyboard and an editing session begins for that text object. When the user taps another text objector taps a button to end editing, the current text object resigns first-responder status. If no other text object isselected, the system hides the keyboard; if, on the other hand, the user selects another text object, it becomesfirst 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 presentsits view using the "form sheet" style, the keyboard, once shown, is not hidden until the user taps the dismisskey or the modal view controller is programmatically dismissed. The purpose of this behavior is to avoidexcessive animations as a user moves between views that are largely, but not entirely, text fields. Anotherexception involves custom input views. An input view is a substitute for system keyboards that is assigned tothe inputView property of a text view or a custom view. When there are input views, UIKit might swap outthe keyboard even when a text object is first responder, and it might show a keyboard-like input view on thedeveloper'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 responder—textFieldShouldBeginEditing: (text field) andtextViewShouldBeginEditing: (text view).

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

22

Managing Text Fields and Text Views

Page 23: Text programming guide for iOS

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

2. Just after a text object becomes first responder—textFieldDidBeginEditing: (text field) andtextViewDidBeginEditing: (text view).

The delegate can respond to this message by updating state information or, for example, by showing anoverlay view during the editing session.

3. During the editing session—various.

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 textchanges. The delegate of a text field can receive a textFieldShouldClear: message when the usertaps the clear button of a text field; the delegate returns a Boolean value indicating whether the textshould be cleared.

4. Just before a text object resigns first responder—textFieldShouldEndEditing: (text field) andtextViewShouldEndEditing: (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 ifthe 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, thetext field class sends a textFieldShouldReturn: message to the delegate to ask whether it shouldresign first responder.

5. Just after text a object resigns first responder—textFieldDidEndEditing: (text field) andtextViewDidEndEditing: (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 andtext fields by observing notifications. (They can’t, however, approve or deny the transition to a new status.)The notifications have names such as UITextFieldTextDidBeginEditingNotification,UITextViewTextDidEndEditingNotification, and UITextViewTextDidChangeNotification. Aswith textFieldDidEndEditing: and textViewDidEndEditing:, the primary reason for observing andhandling the UITextFieldTextDidEndEditingNotification andUITextViewTextDidEndEditingNotification notifications is to access the text in the associated textfield or text view. See UITextField Class Reference and UITextView Class Reference to learn more about thenotifications posted by these classes.

Managing Text Fields and Text ViewsThe Sequence of Messages to the Delegate

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

23

Page 24: Text programming guide for iOS

Configuring Text Fields and Text ViewsAs with any view object provided by the UIKit framework, you usually need to configure text fields and textviews before they’re displayed. You can configure them either programmatically or using the attribute inspectorof 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 characteristics—Text color, alignment, font family, font typeface, and font size.

● Keyboard—Keyboard type, return key name, secure text entry, and auto-enabled return key, all of whichare declared by the UITextInputTraits protocol. (Note that an auto-enabled return key associatedwith a text view acts as a carriage-return key when tapped.) For more information, see “Configuring theKeyboard for Text Objects” (page 37).

● Text-field specific—Border, background image, disabled image, clear button, and placeholder text. As aUIControl object, text fields also have highlighted, selected, enabled, and other properties.

● Text-view specific—Editable status, data detectors (for phone numbers and URL links). Because a textview inherits from UIScrollView, you can also manage scroll-view behavior by setting the appropriateproperties.

Tracking Multiple Text Fields or Text ViewsAll methods of the UITextFieldDelegate or UITextViewDelegate protocols have a parameter thatidentifies the text field or text view with the change in first-responder status, the change in value, or any otherchange that is the reason for the delegation message. If there is only one text object in the currently displayedview, the identity of the text object referenced by the parameter is obvious. However, if the currently displayedview has multiple text fields or text views, the delegate must find a way to identify the text object that is thesubject of a delegation message.

You can make this determination using one of two approaches: outlets or tags. For the outlet approach, declarean outlet instance variable (using the IBOutlet keyword) and then make an outlet connection. In yourdelegation method, test whether the passed-in text object is the same object referenced by the outlet, usingpointer comparison. For example, say you declare and connect an outlet named SSN. Your code might looksomething like Listing 3-1.

Listing 3-1 Identifying the passed-in text object using an outlet

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {

if (textField == SSN) {

Managing Text Fields and Text ViewsConfiguring Text Fields and Text Views

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

24

Page 25: Text programming guide for iOS

// .....

return NO;

}

return YES;

}

Defining outlet connections for the text objects in a view is especially useful, even essential, when you needto 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 attributeinspector of Interface Builder. (The tag property is declared by UIView.) In a delegation method, you can usea switch statement to evaluate the tag value of the passed-in text object and proceed accordingly (as shownin 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....

}

}

Managing Text Fields and Text ViewsTracking Multiple Text Fields or Text Views

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

25

Page 26: Text programming guide for iOS

Getting the Entered Text and Setting TextAfter a user enters or edits text in a text field or text view and the editing session ends, the delegate shouldget the text and store it in the app’s data model. The best delegation methods for accessing entered text aretextFieldDidEndEditing: (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 multipletext fields in a view using tags). The text property of UITextField or UITextView holds the string currentlydisplayed by the text object. The delegate gets the string from this property and stores it in a dictionary objectusing a key defined for each field. If the text field has no string value—that is, the field holds an emptystring—the 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 displayedstring from the text view and stores it in a dictionary. Here the method doesn’t ask the text view to resign firstresponder. (The resignFirstResponder method was called earlier in an action method invoked when theuser tapped a Done button in the view’s user interface.)

Managing Text Fields and Text ViewsGetting the Entered Text and Setting Text

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

26

Page 27: Text programming guide for iOS

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 objects—usually after retrieving them from the app’s datamodel—simply assign the strings to the text property of the text object. For example:

NSString *storedValue = [thePerson objectForKey:MyAppPersonEmailKey];

emailField.text = storedValue;

To do this, it’s 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 FieldsFormatter objects automatically parse strings in a specific format and convert the string to an object representinga number, date, or other value; they also work in reverse, converting NSDate, NSNumber, and similar objectsto a formatted string that represents those object values. The Foundation framework provides the abstractbase class NSFormatter and two concrete subclasses of that class, NSDateFormatter andNSNumberFormatter. 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 coulduse a UIDatePicker object for date input rather than a text field, but a text field with an attached dateformatter is another option.) The code in Listing 3-5 creates an NSDateFormatter object and assigns it to an

Managing Text Fields and Text ViewsUsing Formatters with Text Fields

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

27

Page 28: Text programming guide for iOS

instance variable. It configures the date formatter to use the “short style” for dates, but in a way that is responsiveto changes in calendar, locale, and time zone. It also assigns today’s date in the given format as a placeholderstring 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: %@", [dateFormatterstringFromDate:[NSDate date]]];

// code continues....

}

After you have configured the date formatter, the delegate can call the dateFromString: method on theformatter 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:

Managing Text Fields and Text ViewsUsing Formatters with Text Fields

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

28

Page 29: Text programming guide for iOS

break;

}

}

The use of formatters does not guarantee that the entered string contains valid values—for example, a usercould enter 13 for a month number in the Gregorian calendar. To ensure that the user has entered a correctvalue, the delegate must validate the string as explained in “Validating Entered Text” (page 29). And becausevalidation often requires a known format and range of valid values, if you configure the date formatter as inListing 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 formatpattern 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 callingthe NSDateFormatter method stringFromDate: and then assign that string to the text property of atext field, text view, or label.

For more information on NSDateFormatter and NSNumberFormatter, see Data Formatting Guide .

Validating Entered TextAn app sometimes cannot accept the strings entered in text fields and text views without validating the valuefirst. Perhaps the string must be in a certain format, or the value (after it is converted to a numeric value) mustfall within a certain range. The best delegation methods for validating entered strings aretextFieldShouldEndEditing: for text fields and textViewShouldEndEditing: for text views. Thesemethods are called just before the text field or text view resigns first responder status. Returning NO preventsthat from happening, and consequently the text object remains the focus of editing. If an entered string isinvalid, 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 conformsto the format for such numbers.

Listing 3-7 Validating the format of a text field’s 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:regExoptions:NSRegularExpressionSearch];

if (r.location == NSNotFound) {

Managing Text Fields and Text ViewsValidating Entered Text

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

29

Page 30: Text programming guide for iOS

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 textentered in a text view.

Listing 3-8 Validating a text view’s 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:selfcancelButtonTitle:@"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 thetextField:shouldChangeCharactersInRange:replacementString:method. The code in Listing 3-9verifies that each entered character (string) represents a digit. (You could accomplish the same goal byspecifying a UIKeyboardTypeNumberPad keyboard for the text field.)

Listing 3-9 Validating each character as it’s entered

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

Managing Text Fields and Text ViewsValidating Entered Text

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

30

Page 31: Text programming guide for iOS

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 FieldsOverlay views are small views inserted into the left and right corners of a text field. They act as controls whenusers tap them (frequently they are buttons) and act on the current contents of the text field. Searching andbookmarking are two common tasks for overlay views, but others are possible. This overlay view loads a webbrowser 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 theview an appropriately sized image. If the view is a button or other control, specify a target object, an actionselector, and the triggering control events. Usually you want an overlay view to appear when its text field isthe focus of editing, so assign it to the text field’s leftView or rightView property in the delegate’stextFieldDidBeginEditing: method. You can control when an overlay view appears during the editingsession—for example, before the user begins entering text or only after the user begins entering text—byassigning a UITextFieldViewMode constant to the leftViewMode or rightViewMode property. Listing3-10 illustrates how you might implement an overlay view.

Managing Text Fields and Text ViewsUsing Overlay Views in Text Fields

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

31

Page 32: Text programming guide for iOS

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 thetextFieldDidEndEditing: 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....

Managing Text Fields and Text ViewsUsing Overlay Views in Text Fields

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

32

Page 33: Text programming guide for iOS

}

Tracking the Selection in Text ViewsThe textViewDidChangeSelection: method of UITextViewDelegate lets you track changes to theselections that a user makes in a text view. You can implement the method to obtain the selected substringand do something with it. Listing 3-12 is a whimsical example that makes all characters in the selected substringuppercase.

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:rwithString:upString];

textView.text = newString;

}

Managing Text Fields and Text ViewsTracking the Selection in Text Views

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

33

Page 34: Text programming guide for iOS

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

Loading Local ContentWhen loading local content, you can either create the content dynamically or load it from a file and display itusing the loadData:MIMEType:textEncodingName:baseURL: or loadHTMLString:baseURL:method.The method in Listing 4-1 uses the loadData:MIMEType:textEncodingName:baseURL: method to loadthe 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 NetworkTo 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

Page 35: Text programming guide for iOS

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

Because loading a web resource might take some time, you might display an activity indicator to indicate thatthe load is underway. You can do this by assigning a delegate to the web view and implementing theUIWebViewDelegate methods, as in Listing 4-2. The delegate displays an activity indicator when the loadstarts and hides it when the load ends. If there is a problem with the load, it creates an HTML error messageand, 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];

}

Displaying Web ContentLoading Content From the Network

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

35

Page 36: Text programming guide for iOS

If, after initiating a network-based load request, you must release your web view for any reason, you mustcancel the pending request before releasing the web view. You can cancel a load request using the web view’sstopLoading method. A typical place to include this code would be in the viewWillDisappear: methodof the owning view controller. To determine if a request is still pending, you can check the value in the webview’s 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; // disconnect the delegate as the webviewis hidden

[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

}

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

Displaying Web ContentLoading Content From the Network

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

36

Page 37: Text programming guide for iOS

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

Keyboards and Input MethodsWhenever the user taps in an object capable of accepting text input, the object asks the system to display anappropriate keyboard. Depending on the needs of your program and the user’s preferred language, the systemmight display one of several different keyboards. Although your app cannot control the user’s preferredlanguage (and thus the keyboard’s input method), it can control attributes of the keyboard that indicate itsintended use, such as the configuration of any special keys and its behaviors.

Configuring the Keyboard for Text ObjectsYou configure the attributes of the keyboard directly through the text objects of your app. The UITextFieldand UITextView classes both conform to the UITextInputTraits protocol, which defines the propertiesfor configuring the keyboard. Setting these properties programmatically or in the Interface Builder inspectorwindow 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 keyboardalong with several other keyboard configurations. The default keyboard displays an alphabetical keyboardinitially 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

Page 38: Text programming guide for iOS

offer similar features as the default keyboard but provide additional buttons that are specially suited to particulartasks. However, the phone and numerical keyboards offer a dramatically different layout that is tailored towardsnumerical input.

Figure 5-1 Several different keyboard types

Managing the KeyboardKeyboards and Input Methods

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

38

Page 39: Text programming guide for iOS

To implement the language preferences of different users, iOS also supports different input methods andkeyboard layouts for different languages, some of which are shown in Figure 5-2. The input method and layoutfor the keyboard is determined by the user’s language preferences. Input for some of these keyboards takesplace in multiple stages.

Figure 5-2 Several different keyboards and input methods

keyboard_input.epsText, Web, and Editing Programming Guide for iOSApple, Inc.keyboard_input.tif reduced to 20%

Configuring the Keyboard for Web ViewsAlthough the UIWebView class does not support the UITextInputTraits protocol directly, you can configuresome keyboard attributes for text input elements. For example, you can include autocorrect andauto-capitalization attributes in the definition of an input element to specify the keyboard’s behaviors,as shown in the following example.

Managing the KeyboardKeyboards and Input Methods

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

39

Page 40: Text programming guide for iOS

<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. Todisplay a telephone keypad, an email keyboard, or a URL keyboard, use the tel, email, or url keywords forthe type attribute on an input element, respectively. To display a numeric keyboard, set the value of thepattern 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 showshow 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 KeyboardAlthough many UIKit objects display the keyboard automatically in response to user interactions, your app stillhas some responsibilities for configuring and managing the keyboard. The following sections describe thoseresponsibilities.

Receiving Keyboard NotificationsWhen 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 theUIKeyboardFrameBeginUserInfoKey and UIKeyboardFrameEndUserInfoKey keys; the former givesthe beginning keyboard frame, the latter the ending keyboard frame (both in screen coordinates). You shouldalways use the information in these notifications as opposed to assuming the keyboard is a particular size or

Managing the KeyboardManaging the Keyboard

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

40

Page 41: Text programming guide for iOS

in a particular location. The size of the keyboard is not guaranteed to be the same from one input method toanother and may also change between different releases of iOS. In addition, even for a single language andsystem 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 theinformation inside the keyboard notifications ensures that you always have the correct size and positioninformation.

Figure 5-3 Relative keyboard sizes in portrait and landscape modes

Note: The rectangle contained in the UIKeyboardFrameBeginUserInfoKey andUIKeyboardFrameEndUserInfoKey properties of the userInfo dictionary should be used onlyfor 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 actualbounding 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 keyboardwhen it is visible. For information on how to handle this scenario, see “Moving Content That Is Located Underthe Keyboard” (page 42).

There is no defined relationship between the timing of keyboard notifications and the timing of view-controllertransitions.

Managing the KeyboardManaging the Keyboard

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

41

Page 42: Text programming guide for iOS

Displaying the KeyboardWhen the user taps a view, the system automatically designates that view as the first responder. When thishappens to a view that contains editable text, the view initiates an editing session for that text. At the beginningof that editing session, the view asks the system to display the keyboard, if it is not already visible. If thekeyboard is already visible, the change in first responder causes text input from the keyboard to be redirectedto the newly tapped view.

Because the keyboard is displayed automatically when a view becomes the first responder, you often do notneed to do anything to display it. However, you can programmatically display the keyboard for an editabletext view by calling that view’s becomeFirstResponder method. Calling this method makes the target viewthe 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 currentlythe first responder so that you can dismiss the keyboard later.

Dismissing the KeyboardAlthough it typically displays the keyboard automatically, the system does not dismiss the keyboardautomatically. Instead, it is your app’s 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 usertaps the Return or Done button on the keyboard or taps some other button in your app’s interface. Dependingon how you configured the keyboard, you might need to add some additional controls to your user interfaceto facilitate the keyboard’s dismissal.

To dismiss the keyboard, you call the resignFirstRespondermethod of the text-based view that is currentlythe first responder. When a text view resigns its first responder status, it ends its current editing session, notifiesits delegate of that fact, and dismisses the keyboard. In other words, if you have a variable called myTextFieldthat points to the UITextField object that is currently the first responder, dismissing the keyboard is assimple 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 KeyboardWhen asked to display the keyboard, the system slides it in from the bottom of the screen and positions it overyour app’s content. Because it is placed on top of your content, it is possible for the keyboard to be placed ontop of the text object that the user wanted to edit. When this happens, you must adjust your content so thatthe target object remains visible.

Managing the KeyboardManaging the Keyboard

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

42

Page 43: Text programming guide for iOS

Adjusting your content typically involves temporarily resizing one or more views and positioning them so thatthe text object remains visible. The simplest way to manage text objects with the keyboard is to embed theminside 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. Get the size of the keyboard.

2. Adjust the bottom content inset of your scroll view by the keyboard height.

3. Scroll the target text field into view.

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

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

Figure 5-4 Adjusting content to accommodate the keyboard

Managing the KeyboardManaging the Keyboard

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

43

Page 44: Text programming guide for iOS

Listing 5-1 shows the code for registering to receive keyboard notifications and shows the handler methodsfor those notifications. This code is implemented by the view controller that manages the scroll view, and thescrollView variable is an outlet that points to the scroll view object. The keyboardWasShown: methodgets the keyboard size from the info dictionary of the notification and adjusts the bottom content inset of thescroll view by the height of the keyboard. It also sets the scrollIndicatorInsets property of the scrollview to the same value so that the scrolling indicator won’t be hidden by the keyboard. Note that thekeyboardWillBeHidden:method doesn’t use the keyboard size; it simply sets the scroll view’scontentInsetand scrollIndicatorInsets properties to the default value, UIEdgeInsetsZero.

If the active text field is hidden by the keyboard, the keyboardWasShown: method adjusts the content offsetof the scroll view appropriately. The active field is stored in a custom variable (called activeField in thisexample) 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 actsas 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);

Managing the KeyboardManaging the Keyboard

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

44

Page 45: Text programming guide for iOS

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 variablein the preceding example. During initialization, each text field in the interface sets the view controller as itsdelegate. Therefore, when a text field becomes active, it calls these methods. For more information on textfields 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;

}

Managing the KeyboardManaging the Keyboard

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

45

Page 46: Text programming guide for iOS

There are other ways you can scroll the edited area in a scroll view above an obscuring keyboard. Instead ofaltering the bottom content inset of the scroll view, you can extend the height of the content view by theheight of the keyboard and then scroll the edited text object into view. Although the UIScrollView classhas a contentSize property that you can set for this purpose, you can also adjust the frame of the contentview, as shown in Listing 5-3. This code also uses the setContentOffset:animated: method to scroll theedited 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];

}

Managing the KeyboardManaging the Keyboard

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

46

Page 47: Text programming guide for iOS

Users can copy text, images, or other data in one app and paste that data to another location within the sameapp or in a different app. You can, for example, copy a person’s address in an email message and paste it intothe 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 objectsof 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 pasteoperations 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 UIKitSeveral classes and an informal protocol of the UIKit framework give you the methods and mechanisms youneed to implement copy, cut, and paste operations in your app:

● The UIPasteboard class provides pasteboards: protected areas for sharing data within an app or betweenapps. 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, orpasted into. The default commands of the edit menu are (potentially) Copy, Cut, Paste, Select, and SelectAll. You can also add custom menu items to the edit menu (see “Adding Custom Items to the EditMenu” (page 62)).

● The UIResponder class declares the method canPerformAction:withSender:. Responder classescan 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, thecorresponding UIResponderStandardEditActions method is invoked.

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

47

Copy, Cut, and Paste Operations

Page 48: Text programming guide for iOS

Pasteboard ConceptsA pasteboard is a standardized mechanism for exchanging data within apps or between apps. The most familiaruse 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 isplaced onto a pasteboard.

● When the user chooses the Paste menu command (either in the same or a different app), the data on apasteboard 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 transferdata between apps using custom URL schemes instead of copy, cut, and paste commands; see “Updating YourInfo.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 apasteboard and to read data from a pasteboard. Although these tasks are conceptually simple, they mask anumber 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 followingsections.

Named PasteboardsPasteboards may be public or private. Public pasteboards are called system pasteboards; private pasteboardsare 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 thegeneralPasteboard class method.

● UIPasteboardNameFind is for search operations. The string currently typed by the user in the searchbar (UISearchBar) is written to this pasteboard, and thus can be shared between apps. You can obtainan 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 apppasteboard using pasteboardWithName:create: If you invoke pasteboardWithUniqueName,UIPasteboard gives you a uniquely-named app pasteboard. You can discover the name of a pasteboardthrough its name property.

Copy, Cut, and Paste OperationsPasteboard Concepts

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

48

Page 49: Text programming guide for iOS

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

Pasteboard Owner and ItemsThe object that last put data onto the pasteboard is referred to as the pasteboard owner. Each piece of dataplaced 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 containsboth text and an image. The pasteboard lets you copy the text and the image to the pasteboard as separateitems. 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 thecurrent contents of the pasteboard. Although you may use the addItems: method of UIPasteboard toappend items, the write methods of the class do not append items to the current contents of the pasteboard.

Representations and UTIsPasteboard operations are often carried out between two different apps. Neither app is required to know aboutthe other, including the kinds of data it can handle. To maximize the potential for sharing, a pasteboard canhold multiple representations of the same pasteboard item. For example, a rich text editor might provideHTML, PDF, and plain-text representations of the copied data. An item on a pasteboard includes allrepresentations 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 simplya string that uniquely identifies a particular data type.) The UTI provides a common means to identify datatypes. 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, acustom representation type could be com.myCompany.myApp.myType. For more information on UTIs, seeUniform Type Identifiers Overview .

Copy, Cut, and Paste OperationsPasteboard Concepts

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

49

Page 50: Text programming guide for iOS

For example, suppose an app supported selection of rich text and images. It may want to place on a pasteboardboth 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 differentrepresentations as possible.

A pasteboard reader must find the data type that best suits its capabilities (if any). Typically, this means selectingthe richest type available. For example, a text editor might provide HTML (rich text) and plain-text representationsof copied text data. An app that supports rich text should retrieve the HTML representation and an app thatonly supports plain text should retrieve the plain-text version.

Copy, Cut, and Paste OperationsPasteboard Concepts

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

50

Page 51: Text programming guide for iOS

Change CountThe change count is a per-pasteboard variable that increments every time the contents of the pasteboardchanges—specifically, when items are added, modified, or removed. By examining the change count (throughthe changeCount property), an app can determine whether the current data in the pasteboard is the sameas the data it last received. Every time the change count is incremented, the pasteboard sends a notificationto interested observers.

First Steps: Identify the Selection and Display the Edit MenuIf you are going to copy, cut, or paste something, you first must select it. (A paste operation often operates onan empty selection such a caret, indicating a position within a collection of items.) After selecting an item—andvisually indicating the selection—you should display the edit menu. The edit menu is a system menu that canpotentially have the following commands in it: Copy, Cut, Paste, Select, and Select All. The edit menu pointsat the selection. When the user taps a menu item, the appropriate UIResponderStandardEditActionsmethod 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 Selectionand the Edit Menu” (page 59).

Copying and Cutting the SelectionWhen 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 responder—your customview—implements these methods, but if the first responder doesn’t implement them, the message travels upthe responder chain in the usual fashion. Note that the UIResponderStandardEditActions informalprotocol declares these methods.

Note: Because UIResponderStandardEditActions is an informal protocol, any class in yourapp can implement its methods. But to take advantage of the default behavior for traversing theresponder chain, the class implementing the methods should inherit from UIResponder and shouldbe installed in the responder chain.

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

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

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

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

51

Page 52: Text programming guide for iOS

Binary data must be encapsulated in an NSData object. If you’re going to write another type of object tothe pasteboard, it must be a property-list object—that 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, youcould use the UIImageJPEGRepresentation and UIImagePNGRepresentation functions to convertthe 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 classmethod.

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 pasteboardobject.

6. If the command is Cut (cut: method), remove the object represented by the selection from the app’sdata 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:methodarchives a custom object to obtain an NSData object that it can pass to the pasteboard insetData: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];

}

Copy, Cut, and Paste OperationsCopying and Cutting the Selection

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

52

Page 53: Text programming guide for iOS

}

- (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 SelectionWhen users tap the Paste command of the edit menu, the system invokes the paste:method of the responderobject that implements it. Usually the first responder—your custom view—implements this method, but if thefirst responder doesn’t 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 appsupports. Then you add the pasted object to the app’s data model and display the new object in the view inthe user-indicated location. This operation involves the following steps (which assume a single pasteboarditem):

1. Obtain a pasteboard object.

In many cases, this is the general pasteboard, which you can get through the generalPasteboard classmethod.

2. Verify that the first pasteboard item contains data in a representation that your app can handle by callingthe containsPasteboardTypes: method or the pasteboardTypes method and then examining thereturned array of types.

Note that you should have already performed this step in your implementation ofcanPerformAction:withSender:.

3. If the first item of the pasteboard contains data that the app can handle, call one of the following methodsto read it:

Copy, Cut, and Paste OperationsPasting the Selection

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

53

Page 54: Text programming guide for iOS

● 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. Add the object to the app’s data model.

5. 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 combinedcut: and copy: methods. The custom view first sees whether the general pasteboard holds its customrepresentation of data; if it does, it then reads the data from the pasteboard, adds it to the app’s data model,and marks part of itself—the current selection—for 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 *)[NSKeyedUnarchiverunarchiveObjectWithData:tileData];

if (theTile) {

theTile.tileOrigin = self.currentSelection;

[tiles addObject:theTile];

CGRect tileRect = [self rectFromOrigin:currentSelectioninset:TILE_INSET];

[self setNeedsDisplayInRect:tileRect];

}

}

}

Ending an OperationWhen your implementation of the cut:, copy: or paste: command returns, the edit menu is automaticallyhidden. You can programmatically keep it visible if you want. For more information, see “Dismissing the EditMenu” (page 63)

Copy, Cut, and Paste OperationsEnding an Operation

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

54

Page 55: Text programming guide for iOS

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

Input Views and Input Accessory ViewsThe UIKit framework includes support for custom input views and input accessory views. Your app can substituteits 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 inputaccessory view to the system keyboard or to a custom input view; this accessory view runs along the top ofthe main input view and can contain, for example, controls that affect the text in some way or labels thatdisplay some information about the text.

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

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

@property (readonly, retain) UIView *inputView;

@property (readonly, retain) UIView *inputAccessoryView;

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

The UITextView class redeclares the inputView and inputAccessoryView properties as readwrite.Clients of UITextView objects need only obtain the input and input-accessory views—either by loading anib file or creating the views in code—and 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

Page 56: Text programming guide for iOS

subclasses that inherit from UIResponder) should redeclare one or both of these properties and their backinginstance variables and override the getter method for the property—that is, don’t synthesize the properties’accessor methods. In their getter-method implementations, they should return it the view, loading or creatingit if it doesn’t already exist.

You have a lot of flexibility in defining the size and content of an input view or input accessory view. Althoughthe height of these views can be what you’d like, they should be the same width as the system keyboard. IfUIKit 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 ascontrols) that input views and input accessory views may have. For more guidance on input views and inputaccessory 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 atruntime get the app’s main bundle and call loadNibNamed:owner:options: on it, passing the name of thenib file, the File’s Owner for the nib file, and any options. This method returns an array of the top-level objectsin 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 inputAccessoryViewgetter 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;

}

Custom Views for Data InputInput Views and Input Accessory Views

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

56

Page 57: Text programming guide for iOS

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

Just as it does with the system keyboard, UIKit posts UIKeyboardWillShowNotification,UIKeyboardDidShowNotification, UIKeyboardWillHideNotification, andUIKeyboardDidHideNotification notifications. The object observing these notifications can get geometryinformation 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 ClicksYou can play standard system keyboard clicks when a user taps in your custom input views and keyboardaccessory views. First, adopt the UIInputViewAudioFeedback protocol in your input view. Then, call theplayInputClick method when responding to a key tap in the view.

Adopting the UIInputViewAudioFeedback ProtocolPerform 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 subclassconforms to the UIInputViewAudioFeedback protocol, as follows:

@interface KeyboardAccessoryView : UIView <UIInputViewAudioFeedback> {

}

2. In the implementation file for your UIView subclass, implement the enableInputClicksWhenVisiblemethod, 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.

Custom Views for Data InputPlaying Input Clicks

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

57

Page 58: Text programming guide for iOS

Playing Input ClicksTo play an input click for a key tap in a custom input or keyboard accessory view, first ensure that view adoptsthe UIInputViewAudioFeedback protocol as described in “Adopting the UIInputViewAudioFeedbackProtocol” (page 57). Then, for each tap that you want to provide a click sound for, call the playInputClickmethod 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 asneeded. (For information on audio sessions, see Audio Session Programming Guide .)

Custom Views for Data InputPlaying Input Clicks

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

58

Page 59: Text programming guide for iOS

The edit menu is a contextual menu that is displayed to offer commands that can be performed on a selectionsuch 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 addcustom menu items to the edit menu to perform other kinds of actions on selections.

Managing the Selection and the Edit MenuTo copy or cut something in a view, or to do anything else with it, that “something” must be selected. It canbe a range of text, an image, a URL, a color, or any other representation of data, including custom objects. Youmust manage the selection of objects in that view yourself. If the user selects an object in the view by makinga 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 possiblefor users to select multiple objects in your view for copy-cut-paste operations, you must implement thatmultiple-selection behavior.

Note: Techniques for handling touch events, including the use of gesture recognizers, are discussedin Event Handling Guide for iOS .

When your app determines that the user has requested the edit menu—which could be the action of makinga selection—you should complete the following steps to display the menu:

1. Call the sharedMenuController class method of UIMenuController to get the global menu-controllerinstance.

2. Compute the boundaries of the selection and with the resulting rectangle call thesetTargetRect:inView:method. The edit menu is displayed above or below this rectangle, dependinghow close the selection is to the top or bottom of the screen.

3. Call the setMenuVisible:animated: method (with YES for both arguments) to animate the display ofthe edit menu above or below the selection.

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

59

Displaying and Managing the Edit Menu

Page 60: Text programming guide for iOS

Listing 8-1 illustrates how you might display the edit menu in an implementation of thetouchesEnded:withEvent: method for handling copy, cut, and paste operations. (Note that the exampleomits the section of code that handles the selection.) This code snippet also shows the custom view sendingitself 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 correspondingUIResponderStandardEditActions method implementations (copy:, paste:, and so on). Before themenu is displayed, however, the system sends a canPerformAction:withSender: message to the firstresponder, which in many cases is the custom view itself. In its implementation of this method, the responderevaluates whether the command (indicated by the selector in the first argument) is applicable in the currentcontext. For example, if the selector is paste: and there is no data in the pasteboard of a type the view canhandle, the responder should return NO to suppress the Paste command. If the first responder does notimplement the canPerformAction:withSender: method, or does not handle the given command, themessage travels up the responder chain.

Listing 8-2 shows an implementation of thecanPerformAction:withSender:method that looks for messagematching the cut:, copy:, and paste: selectors; it enables or disables the Copy, Cut, and Paste menucommands based on the current selection context and, for paste, the contents of the pasteboard.

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

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

60

Page 61: Text programming guide for iOS

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 achance 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 thiscase the responder can, while the menu is still visible, call update on the menu controller; this results in thereinvocation of canPerformAction:withSender: on the first responder.

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

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

61

Page 62: Text programming guide for iOS

Adding Custom Items to the Edit MenuYou can add a custom item to the edit menu. When users tap this item, a command is issued that affects thecurrent target in an app-specific way. The UIKit framework accomplishes this through the target-actionmechanism. The tap of an item results in an action message being sent to the first object in the responderchain 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 mustinitialize a UIMenuItem instance with these properties, add the instance to the menu controller’s array ofcustom menu items, and then implement the action method for handling the command in the appropriateresponder subclass.

Other aspects of implementing a custom menu item are common to all code that uses the singletonUIMenuController object. In a custom or overridden view, you set the view to be the first responder, getthe shared menu controller, set a target rectangle, and then display the edit menu with a call tosetMenuVisible:animated:. The simple example in Listing 8-3 adds a custom menu item for changing acustom view’s 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:)];

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

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

62

Page 63: Text programming guide for iOS

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 tospecify the direction the arrow attached to the edit menu points at its target rectangle.

Dismissing the Edit MenuWhen 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 orthe user taps in another area of the screen. If you have state or a display that depends on whether the editmenu is visible, you should listen for the notification namedUIMenuControllerWillHideMenuNotificationand take an appropriate action.

Displaying and Managing the Edit MenuDismissing the Edit Menu

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

63

Page 64: Text programming guide for iOS

The UIKit framework includes several classes whose purpose is to display text in an app’s user interface:UITextView, UITextField, UILabel, and UIWebView, as described in “Displaying Text Content in iOS” (page11). Text views, created from the UITextView class, are meant to display large amounts of text. UnderlyingUITextView is a powerful layout engine called Text Kit. If you need to customize the layout process or youneed to intervene in that behavior, you can use Text Kit. For smaller amounts of text and special needs requiringcustom solutions, you can use alternative, lower-level technologies, as described in “Lower Level Text-HandlingTechnologies” (page 79).

Text Kit is a set of classes and protocols in the UIKit framework providing high-quality typographical servicesthat 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 speedand power. UITextView is fully integrated with Text Kit; it provides editing and display capabilities that enableusers to input text, specify formatting attributes, and view the results. The other Text Kit classes provide textstorage and layout capabilities. Figure 9-1 shows the position of Text Kit among other iOS text and graphicsframeworks.

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 architecturethat 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

Page 65: Text programming guide for iOS

Primary Text Kit ObjectsThe data flow paths among the primary Text Kit objects are shown in Figure 9-2. Text views are instances ofUITextView class, text containers are instances of NSTextContainer class, the layout manager is an instanceof NSLayoutManager class, and the text storage is an instance of NSTextStorage class. In Text Kit, anNSTextStorage object stores the text that is displayed by a UITextView object and laid out by anNSLayoutManager 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 definesa 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 thatcan be filled with text, it maintains an array of Bezier paths that are exclusion zones within its area where textis not laid out. As it is laid out, text flows around the exclusion paths, providing a means to include graphicsand other non-text layout elements.

NSTextStorage defines the fundamental storage mechanism of the Text Kit’s extended text-handling system.NSTextStorage is a subclass of NSMutableAttributedString that stores the characters and attributesmanipulated by the text system. It ensures that text and attributes are maintained in a consistent state acrossediting operations. In addition to storing the text, an NSTextStorage object manages a set of clientNSLayoutManager objects, notifying them of any changes to its characters or attributes so that they can relayand redisplay the text as needed.

An NSLayoutManager object orchestrates the operation of the other text handling objects. It intercedes inoperations that convert the data in an NSTextStorage object to rendered text in a view’s display area. Itmaps Unicode character codes to glyphs and oversees the layout of the glyphs within the areas defined byNSTextContainer objects.

Using Text Kit to Draw and Manage TextPrimary Text Kit Objects

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

65

Page 66: Text programming guide for iOS

Note: NLayoutManager,NSTextStorage, andNSTextContainer can be accessed from subthreadsas long as the app guarantees the access from a single thread.

For reference information aboutUITextView, seeUITextViewClass Reference .NSTextContainer is describedin NSTextContainer Class Reference for iOS , NSLayoutManager in NSLayoutManager Class Reference for iOS ,and NSTextStorage in NSTextStorage Class Reference for iOS .

Text AttributesText Kit handles three kinds of text attributes: character attributes, paragraph attributes, and documentattributes. Character attributes include traits such as font, color, and subscript, which can be associated withan individual character or a range of characters. Paragraph attributes are traits such as indentation, tabs, andline spacing. Document attributes include documentwide traits such as paper size, margins, and view zoompercentage.

Character AttributesAn attributed string stores character attributes as key-value pairs in NSDictionary objects. The key is anattribute name, represented by an identifier (an NSString constant) such as NSFontAttributeName. Figure9-3 shows an attributed string with an attribute dictionary applied to a range within the string.

Figure 9-3 Composition of an attributed string

ns_attributed_string.epsCocoa_Text_ArchitectureApple, Inc.

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 classprovides methods that take a character index and return the associated attribute dictionary and the range towhich its attribute values apply, such as attributesAtIndex:effectiveRange:.

Using Text Kit to Draw and Manage TextText Attributes

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

66

Page 67: Text programming guide for iOS

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

Paragraph AttributesParagraph attributes affect the way the layout manager arranges lines of text into paragraphs on a page. Thetext system encapsulates paragraph attributes in objects of the NSParagraphStyle class. The value of oneof the predefined character attributes, NSParagraphStyleAttributeName, points to an NSParagraphStyleobject containing the paragraph attributes for that character range. Attribute fixing ensures that only oneNSParagraphStyle object pertains to the characters throughout each paragraph.

Paragraph attributes include traits such as alignment, tab stops, line-breaking mode, and line spacing (alsoknown as leading ).

Document AttributesDocument 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 documentattributes, NSAttributedString initialization methods such as initWithRTF:documentAttributes:can populate an NSDictionary object that you provide with document attributes derived from a stream ofRTF 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 themessage.

Attribute FixingEditing attributed strings can cause inconsistencies that must be cleaned up by attribute fixing. The UIKitextensions to NSMutableAttributedString define the fixAttributesInRange: method to fixinconsistencies among attachment, character, and paragraph attributes. These methods ensure that attachmentsdon’t remain after their attachment characters are deleted, that character attributes apply only to charactersavailable in that font, and that paragraph attributes are consistent throughout paragraphs.

Using Text Kit to Draw and Manage TextText Attributes

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

67

Page 68: Text programming guide for iOS

Changing Text Storage ProgrammaticallyAn NSTextStorage object serves as the character data repository for Text Kit. The format for this data is anattributed string, which is a sequence of characters (in Unicode encoding) and associated attributes (such asfont, color, and paragraph style). The classes that represent attributed strings are NSAttributedString andNSMutableAttributedString, of which NSTextStorage is a subclass. As described in “CharacterAttributes” (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 asNSFontAttributeName), and the associated value specifies the characteristicsof 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 abeginEditing 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 amessage, the text storage object invokesedited:range:changeInLength: to track the range of its charactersaffected since it received the beginEditing message.

In the third stage, when you’re done changing the text storage object, you send it an endEditing message.This causes it to sends out the delegate messagetextStorage:willProcessEditing:range:changeInLength: and invoke its own processEditingmethod, 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 methodtextStorage:didProcessEditing:range:changeInLength:, giving the delegate an opportunity toverify and possibly change the attributes. (Although the delegate can change the text storage object’s characterattributes in this method, it cannot change the characters themselves without leaving the text storage in aninconsistent state.) Finally, the text storage object sends theprocessEditingForTextStorage:edited:range:changeInLength:invalidatedRange: messageto each associated layout manager—indicating the range in the text storage object that has changed, alongwith the nature of those changes. The layout managers in turn use this information to recalculate their glyphlocations and redisplay if necessary.

Working with Font ObjectsA computer font is a data file in a format such as OpenType or TrueType, containing information describing aset of glyphs, as described in “Characters and Glyphs” (page 15), and various supplementary information usedin glyph rendering. The UIFont class provides the interface for getting and setting font information. A UIFontinstance provides access to the font’s characteristics and glyphs. Text Kit combines character information with

Using Text Kit to Draw and Manage TextChanging Text Storage Programmatically

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

68

Page 69: Text programming guide for iOS

font information to choose the glyphs used during text layout. You use font objects by passing them to methodsthat accept them as a parameter. Font objects are immutable, so it is safe to use them from multiple threadsin your app.

You don’t create UIFont objects using the alloc and init methods; instead, you usepreferredFontForTextStyle: with a text style constant or fontWithName:size:. You can also use afont descriptor to create a font with fontWithDescriptor:size:. These methods check for an existing fontobject with the specified characteristics, returning it if there is one. Otherwise, they look up the font datarequested and create the appropriate font object.

Text StylesText styles, introduced in iOS 7, are semantic descriptions of the intended uses for fonts and are implementedby a mechanism known as Dynamic Type. Text styles are organized by use and represented by constantsdefined in UIFontDescriptor.h, as shown in Table 9-1. The actual font used for the purpose described bya text style can vary based on a number of dynamic considerations, including the user’s content size categorypreference, which is represented by the UIApplication property preferredContentSizeCategory. Toacquire a font object for a given text style, you pass the corresponding constant to the UIFont methodpreferredFontForTextStyle:. To acquire a font descriptor for a text style, pass the constant to theUIFontDescriptormethod preferredFontDescriptorWithTextStyle:. (See “Font Descriptors” (page70) for more information about font descriptors.)

Table 9-1 Text style constants

UsageConstant

The font used for headings.UIFontTextStyleHeadline

The font used for subheads.UIFontTextStyleSubheadline

The font used for body text.UIFontTextStyleBody

The font used for footnotes.UIFontTextStyleFootnote

The font used for standard captions.UIFontTextStyleCaption1

The font used for alternate captions.UIFontTextStyleCaption2

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

Using Text Kit to Draw and Manage TextWorking with Font Objects

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

69

Page 70: Text programming guide for iOS

preferredFontForTextStyle:, the specific font returned includes traits which vary according to userpreferences and context, including tracking (letter-spacing) adjustments, in addition to being tuned for theuse 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 userinterface elements, such as buttons, bars, and labels. Naturally, you need to choose text styles that look rightin your app. It’s also important to observe the UIContentSizeCategoryDidChangeNotification so thatyou can re–lay out the text when the user changes the content size category. When your app receives thatnotification, it should send the invalidateIntrinsicContentSize message to views positioned by AutoLayout or send setNeedsLayout to user interface elements positioned manually. And it should invalidatepreferred fonts or font descriptors and acquire new ones as needed.

Font DescriptorsFont descriptors, instantiated from the UIFontDescriptor class, provide a way to describe a font with adictionary of attributes and are used to create UIFont objects. In particular, you can make a UIFont objectfrom a font descriptor, you can get a descriptor from a UIFont object, and you can change a descriptor anduse it to make a new font object. You can also use a font descriptor to specify custom fonts provided by anapp.

Font descriptors can be archived, which is an advantage working with text styles. You should not cache fontobjects specified by text styles because they are dynamic—their characteristics vary over time according touser preferences. But you can cache a font descriptor to preserve a description of a font, and then unarchiveit 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 thencreate instances of fonts matching those attributes, such as names, traits, languages, and other features. Forexample, you can use a font descriptor to retrieve all the fonts matching a given font family name, using thefamily 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];

Using Text Kit to Draw and Manage TextWorking with Font Objects

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

70

Page 71: Text programming guide for iOS

ThematchingFontDescriptorsWithMandatoryKeys:method as shown returns an array of font descriptorsfor 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 asbold, italic, expanded, and condensed. You can use font descriptors to modify particular traits, as shown inListing 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 tospecify the bold trait, and finally uses the UIFont class method fontWithDescriptor:size: to return anactual font object for the body text style with a bold trait. Passing a size value of 0.0 withfontWithDescriptor:size: specifies that the size attribute originally returned with the font descriptor ispreserved. This behavior is desired, of course, because the font size is determined by the dynamic typemechanism.

Using Text Kit to Draw and Manage TextWorking with Font Objects

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

71

Page 72: Text programming guide for iOS

Querying Font MetricsUIFont defines a number of methods for accessing a font’s metrics information, when that information isavailable. Properties such as ascender, capHeight, xHeight, and so on, all correspond to standard fontmetrics information. Figure 9-4 shows how the font metrics apply to glyph dimensions, and Table 9-2 listsproperty names that correlate with various metrics. See the property descriptions for more specific information.

Figure 9-4 Font metrics

Table 9-2 Font metrics and related UIFont methods

PropertiesFont metric

xHeightX-height

ascenderAscent

capHeightCap height

lineHeightLine height

descenderDescent

pointSizePoint size

Using Text Kit to Draw and Manage TextWorking with Font Objects

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

72

Page 73: Text programming guide for iOS

Laying Out TextThe layout manager object, instantiated from the NSLayoutManager class, is the central controlling objectfor 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 ofNSMutableAttributedString, provides part of the model, holding a string of text characters with attributessuch as typeface, style, color, and size. NSTextContainer can also be considered part of the model becauseit models the geometric layout of the page on which the text is laid out. UITextView (or another UIViewobject) provides the view in which the text is displayed. NSLayoutManager serves as the controller for thetext system because it translates characters in the text storage object into glyphs, lays them out in linesaccording to the dimensions of one or more text container objects, and coordinates the text display in one ormore text view objects.

The Layout ProcessThe layout manager performs text layout in two separate steps: glyph generation and glyph layout. The layoutmanager performs both layout steps lazily, that is, on an as-needed basis. Accordingly, some NSLayoutManagermethods cause glyph generation to happen, while others do not, and the same is true with glyph layout. Afterit generates glyphs and after it calculates their layout locations, the layout manager caches the information toimprove performance of subsequent invocations.

The layout manager caches glyphs, attributes, and layout information. It keeps track of ranges of glyphs thathave been invalidated by changes to the characters in the text storage. There are two ways in which a characterrange 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 messagerequiring knowledge of glyphs or layout in an invalidated range, it generates the glyphs or recalculates thelayout as necessary.

Using Text Kit to Draw and Manage TextLaying Out Text

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

73

Page 74: Text programming guide for iOS

Generating Line Fragment RectanglesThe layout manager lays text within an NSTextContainer object in lines of glyphs. The layout of these lineswithin the text container is determined by its shape and by any exclusion paths it contains. Wherever the linefragment rectangle intersects a region defined by an exclusion path, the lines in those parts must be shortenedor fragmented; if there’s a gap across the entire region, the lines that would overlap it have to be shifted tocompensate.

The layout manager proposes a rectangle for a given line and then asks the text container to adjust the rectangleto fit. The proposed rectangle usually spans the text container’s bounding rectangle, but it can be narroweror wider, and it can also lie partially or completely outside the bounding rectangle. The message that the layoutmanager sends the text container to adjust the proposed rectangle islineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect:, which returnsthe largest rectangle available for the proposed rectangle, based on the direction in which text is laid out. Italso returns a rectangle containing any remaining space, such as the space left on the other side of a hole orgap in the text container.

The layout manager makes one final adjustment when it actually fits text into the rectangle. This adjustmentis a small amount fixed by the text container, called the line fragment padding, which defines the portion oneach end of the line fragment rectangle left blank. Text is inset within the line fragment rectangle by thisamount (the rectangle itself is unaffected). Padding allows for small-scale adjustment of the text container’sregion at the edges (and around any holes) and keeps text from directly abutting any other graphics displayednear the region. You can change the padding from its default value with the lineFragmentPadding property.Note that line fragment padding isn’t a suitable means for expressing margins. For document margins, youshould set the UITextView object’s position and size within its enclosing view. And for text margins, youshould set the textContainerInset property of the text view. In addition, you can set indentation valuesfor individual paragraphs using NSMutableParagraphStyle properties such as headIndent.

In addition to returning the line fragment rectangle itself, the layout manager returns a rectangle called theused rectangle. This is the portion of the line fragment rectangle that actually contains glyphs or other marksto be drawn. By convention, both rectangles include the line fragment padding and the interline space (whichis calculated from the font’s line height metrics and the paragraph’s line spacing parameters). However, theparagraph spacing (before and after) and any space added around the text, such as that caused by center-spacedtext, are included only in the line fragment rectangle, and are not included in the used rectangle.

Specifying Exclusion PathsThe text container maintains an array of UIBezierPath objects representing the exclusion paths inside thereceiver's bounding rectangle. When the layout manager sends the text container alineFragmentRectForProposedRect:atIndex:writingDirection:remainingRect: message

Using Text Kit to Draw and Manage TextLaying Out Text

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

74

Page 75: Text programming guide for iOS

proposing a line fragment rectangle intersecting one of the regions defined by the exclusion paths, the textcontainer returns an adjusted line fragment rectangle excluding that region. This process is illustrated in Figure9-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 youdrag a text view from the object library in Interface Builder. The UITextView object vends the other objectsand 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 namedtextContainer.

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];

Using Text Kit to Draw and Manage TextLaying Out Text

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

75

Page 76: Text programming guide for iOS

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

[self.view addSubview:textView];

This configuration is limited by having only one text container and one text view. In such an arrangement, thetext flows uninterrupted within the area defined by the text container. Page breaks, multicolumn layout, andmore complex layouts can’t be accommodated by this arrangement.

By using multiple text containers, each with an associated text view, more complex layout arrangements arepossible. 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 embeddedin 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 document’s pages.

Using Text Kit to Draw and Manage TextLaying Out Text

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

76

Page 77: Text programming guide for iOS

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 containers—one foreach 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 managerinforms its delegate that it has finished filling the container. The delegate can check to see whether there’smore text that needs to be laid out and add another text container if necessary. The layout manager proceedsto 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.

Using Text Kit to Draw and Manage TextLaying Out Text

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

77

Page 78: Text programming guide for iOS

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

Figure 9-9 Object configuration for multiple views of the same text

Using Text Kit to Draw and Manage TextLaying Out Text

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

78

Page 79: Text programming guide for iOS

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

Simple Text DrawingIn addition to the UIKit classes for displaying and editing text, iOS also includes several ways to draw textdirectly on the screen. The easiest and most efficient way to draw simple strings is using the UIKit additionsto the NSString class, which is in a category named UIStringDrawing. These extensions include methodsfor drawing strings using a variety of attributes wherever you want them on the screen. There are also methodsfor computing the size of a rendered string before you actually draw it, which can help you lay out your appcontent more precisely.

Important: There are some good reasons to avoid drawing text directly in favor of using the text objectsof the UIKit framework. One is performance. Although, a UILabel object also draws its static text, it drawsit only once whereas a text-drawing routine is typically called repeatedly. Text objects also afford moreinteraction; for example, they are selectable.

The methods of UIStringDrawing draw strings at a given point (for single lines of text) or within a specifiedrectangle (for multiple lines). You can pass in attributes used in drawing—for example, font, line-break mode,and baseline adjustment. The methods of UIStringDrawing allow you to adjust the position of the renderedtext precisely and blend it with the rest of your view’s content. They also let you compute the boundingrectangle 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 classstores 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 asubclass of CALayer) its properties are inherently capable of animation. Core Animation is associated with theQuartzCore framework. Because instances of CATextLayer know how to draw themselves in the currentgraphics context, you don’t 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

Page 80: Text programming guide for iOS

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

Core TextCore Text is a technology for custom text layout and font management. App developers typically have no needto use Core Text directly. Text Kit is built on top of Core Text, giving it the same advantages, such as speed andsophisticated typographic capability. In addition, Text Kit provides a great deal of infrastructure that you mustbuild 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 byapps that have their own layout engines—for example, a word processor that has its own page layout enginecan 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 Foundation—similar inthat it is procedural (ANSI C) but is based on object-like opaque types. This API is integrated with both CoreFoundation and Core Graphics. For example, Core Text uses Core Foundation and Core Graphics objects inmany 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 parametersof Core Text functions.

Note: If you use Core Text or Core Graphics to draw text, remember that you must apply a fliptransform to the current text matrix to have text displayed in its proper orientation—that is, withthe drawing origin at the upper-left corner of the string’s bounding box.

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

Core Text Layout Opaque TypesCore 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 astring backing the displayed text and includes properties (or, “attributes”) that define stylistic aspects of thecharacters in the string—for example, font and color. The graphics path defines the shape of a frame of text,which is equivalent to a paragraph.

Lower Level Text-Handling TechnologiesCore Text

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

80

Page 81: Text programming guide for iOS

Core Text objects at runtime form a hierarchy that is reflective of the level of the text being processed (seeFigure 10-1 (page 81)). At the top of this hierarchy is the framesetter object (CTFramesetterRef). With anattributed 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 asalignment, tab stops, line spacing, indentation, and line-breaking mode.

To generate frames, the framesetter calls a typesetter object (CTTypesetterRef). The typesetter convertsthe characters in the attributed string to glyphs and fits those glyphs into the lines that fill a text frame. (Aglyph 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. Aglyph run is a series of consecutive glyphs that have the same attributes and direction. Although a typesetterobject 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 withouthaving to go through the CTFramesetter object. You simply position the origin of the text on the text baselineand request the line object to draw itself.

Core Text Font Opaque TypesFonts are essential to text processing in Core Text. The typesetter object uses fonts (along with the sourceattributed string) to convert glyphs from characters and then position those glyphs relative to one another. Agraphics context is central to fonts in Core Text. You can use graphics-context functions to set the current fontand draw glyphs; or you can create a CTLine object from an attributed string and use its functions to drawinto the graphics context. The Core Text font system handles Unicode fonts natively.

The font system includes objects of three opaque types:CTFont,CTFontDescriptor, andCTFontCollection:

Lower Level Text-Handling TechnologiesCore Text

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

81

Page 82: Text programming guide for iOS

● Font objects (CTFontRef) are initialized with a point size and specific characteristics (from a transformationmatrix). You can query the font object for its character-to-glyph mapping, its encoding, glyph data, andmetrics such as ascent, leading, and so on. Core Text also offers an automatic font-substitution mechanismcalled font cascading.

● Font descriptor objects (CTFontDescriptorRef) are typically used to create font objects. Instead ofdealing with a complex transformation matrix, they allow you to specify a dictionary of font attributesthat include such properties as PostScript name, font family and style, and traits (for example, bold oritalic).

● Font collection objects (CTFontCollectionRef) are groups of font descriptors that provide servicessuch as font enumeration and access to global and custom font collections.

It’s possible to convert UIFont objects to CTFont objects by calling CTFontCreateWithName, passing thefont name and point size encapsulated by the UIFont object.

Core Graphics Text DrawingCore 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 thatyou use one of the system’s other technologies for drawing text. However, if circumstances require it, you candraw 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 setthe text color. You then set the text matrix (CGContextSetTextMatrix) and draw the text usingCGContextShowGlyphsAtPoint.

For more information about these functions and their use, seeQuartz 2DProgrammingGuide andCoreGraphicsFramework Reference .

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

Lower Level Text-Handling TechnologiesCore Graphics Text Drawing

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

82

Page 83: Text programming guide for iOS

Note: In addition to the NSString regular-expression feature described here, iOS provides morecomplete support for regular expressions with the NSRegularExpression class. The ICUUser Guidedescribes 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 otherNSStringCompareOptions options you may specify are NSCaseInsensitiveSearch andNSAnchoredSearch. If a regular-expression search does not find a match or the regular-expression syntax ismalformed, 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, certainregular-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, anddiacritic-insensitive search are not available and capture groups are not supported.

Lower Level Text-Handling TechnologiesFoundation-Level Regular Expressions

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

83

Page 84: Text programming guide for iOS

When testing the returned range, you should be aware of certain behavioral differences between searchesbased on literal strings and searches based on regular-expression patterns. Some patterns can successfullymatch 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 SupportIn case the NSString support for regular expressions is not sufficient for your needs, a modified version ofthe libraries from ICU 4.2.1 is included in iOS at the BSD (nonframework) level of the system. ICU (InternationalComponents 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 withsome 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.

Lower Level Text-Handling TechnologiesICU Regular-Expression Support

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

84

Page 85: Text programming guide for iOS

Simple Text InputAn 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 processingand custom input. Through the available programming interfaces, these apps can acquire features such ascustom 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 charactersbefore that insertion point when they tap the Delete key. An instant-messaging app, for example, could havea 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 inheritsfrom UIResponder, and adopting the UIKeyInput protocol. When an instance of your view class becomesthe first responder, UIKit displays the system keyboard. UIKeyInput itself adopts the UITextInputTraitsprotocol, 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 adoptonly 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 methodsare then available.

To adopt UIKeyInput, you must implement the three methods it declares: hasText, insertText:, anddeleteBackward. To do the actual drawing of the text, you may use any of the technologies summarized inthis chapter. However, for simple text input, such as for a single line of text in a custom control, theUIStringDrawing and CATextLayer APIs are most appropriate.

Listing 10-2 illustrates the UIKeyInput implementation of a custom view class. The textStore property inthis example is an NSMutableString object that serves as the backing store of text. The implementationeither appends or removes the last character in the string (depending on whether an alphanumeric key or theDelete key is pressed) and then redraws textStore.

Listing 10-2 Implementing simple text entry

- (BOOL)hasText {

if (textStore.length > 0) {

return YES;

}

return NO;

}

Lower Level Text-Handling TechnologiesSimple Text Input

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

85

Page 86: Text programming guide for iOS

- (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 UIStringDrawingcategory on NSString.

Communicating with the Text Input SystemThe text input system of iOS manages the keyboard. It interprets taps as presses of specific keys in specifickeyboards 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 anddelete characters at the caret (insertion point).

However, the text input system does more than simple text entry. For example, it manages autocorrection andmultistage input, which are all based upon the current selection and context. Multistage text input is requiredfor ideographic languages such as Kanji (Japanese) and Hanzi (Chinese), which take input from phonetickeyboards. To acquire these features, a custom text view must communicate with the text input system byadopting the UITextInput protocol and implementing the related client-side classes and protocols.

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

86

Page 87: Text programming guide for iOS

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

Overview of the Client Side of Text InputA class that wants to communicate with the text input system must adopt the UITextInput protocol. Theclass 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 andmanages text (as is the case in the sample code analyzed in “A Guided Tour of a UITextInputImplementation” (page 91)). However, if it isn’t the view that draws and manages text, the class thatdoes adopt UITextInput should be able to communicate directly with the view that does. Forsimplicity’s sake, the following discussion refers to the responder class that adopts UITextInputas the text view .

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

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

87

Page 88: Text programming guide for iOS

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 UITextInputmethods that the text view implements. Many of these methodsrequest information about specific text positions and text ranges from the text view and pass the sameinformation back to the class in other method calls. The reasons for these exchanges of text positions and textranges 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. “TextPositions 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 methodsdeclared by the UITextInputDelegate protocol to notify a system-provided input delegate about externalchanges in text and selection. The text input system communicates with a tokenizer object to determine thegranularity of text units—for example, character, word, and paragraph. The tokenizer is an object that adoptsthe UITextInputTokenizer protocol. The text view includes a property (declared by UITextInput) thatholds a reference to the tokenizer.

Text Positions and Text RangesThe 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.

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

88

Page 89: Text programming guide for iOS

Although UITextPosition itself declares no methods or properties, it is an essential part of the informationexchanged between a text document and the text input system. The text input system requires an object torepresent a location in the text instead of, say, an integer or a structure. Moreover, a UITextPosition objectcan serve a practical purpose by representing a position in the visible text when the string backing the texthas 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 customUITextPosition class can account for these invisible characters when locating the string offsets of visiblecharacters. In the simplest case—a plain text document with no embedded objects—a customUITextPositionobject can encapsulate a single offset or index integer.

UITextRange declares a simple interface in which two of its properties are starting and ending customUITextPosition objects. The third property holds a Boolean value that indicates whether the range is empty(that is, has no length).

Tasks of a UITextInput ObjectA class adopting the UITextInput protocol is required to implement most of the protocol’s methods andproperties. With a few exceptions, these methods take custom UITextPosition or UITextRange objectsas parameters or return one of these objects. At runtime the text system invokes these methods and, again inalmost 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 markedtext, if any. Marked text, which is part of multistage text input, represents provisionally inserted text the userhas yet to confirm. It is styled in a distinctive way. The range of marked text always contains within it a rangeof 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 replacethat 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 textrange) 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:

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

89

Page 90: Text programming guide for iOS

● Evaluating text positions. Compare two text positions or return the offset from one text position toanother.

comparePosition:toPosition:

offsetFromPosition:toPosition:

● Answering layout questions. Determine a text position or text range by extending in a given layoutdirection.

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 rangeor 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. Theseenable it to return text styles (font, text color, background color) beginning at a specified text position and toreconcile visible text position and character offset (for those UITextPosition objects where these valuesare not the same).

When changes occur in the text view due to external reasons—that is, they aren't caused by calls from the textinput system—the UITextInput object should send textWillChange:, textDidChange:,selectionWillChange:, and selectionDidChange: messages to the input delegate (which it holds areference to). For example, when users tap a text view and you set the range of selected text to place theinsertion point under the finger, you would send selectionWillChange: before you change the selectedrange, and you send selectionDidChange: after you change the range.

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

90

Page 91: Text programming guide for iOS

TokenizersTokenizers are objects that determine whether a text position is within or at the boundary of a text unit witha given granularity. When queried by the text input system, a tokenizer returns ranges of text units with agiven granularity or the boundary text position for a text unit with a given granularity. Currently definedgranularities are character, word, sentence, paragraph, line, and document; enum constants of theUITextGranularity type represent these granularities. Granularities of text units are always evaluated withreference 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 lastsentence’s worth of context to figure out what the user is trying to type. Or, if the user is pressing the Option-leftarrow key (on an external keyboard), the text system queries the tokenizer to find the information it needs tomove to the previous word.

A tokenizer is an instance of a class that conforms to the UITextInputTokenizer protocol. TheUITextInputStringTokenizer class provides a default base implementation of theUITextInputTokenizerprotocol that is suitable for all supported languages. If you require a tokenizer with an entirely new interpretationof text units of varying granularity, you should adopt UITextInputTokenizer and implement all of itsmethods. Otherwise you should subclass UITextInputStringTokenizer to provide app-specific informationabout layout directions.

When you initialize a UITextInputStringTokenizer object, you supply it with the view adopting theUITextInput protocol. In turn, the UITextInput object should lazily create its tokenizer object in the gettermethod of the tokenizer property.

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

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

91

Page 92: Text programming guide for iOS

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

Subclasses of UITextPosition and UITextRangeEditableCoreTextView creates a custom subclass of UITextPosition called IndexedPosition and acustom subclass of UITextRange called IndexedRange. These subclasses simply encapsulate a single indexvalue 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 thesemethods as well as the methods declared by the UITextRange class.

Listing 10-4 Implementing the IndexedPosition and IndexedRange classes

@implementation IndexedPosition

@synthesize index = _index;

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

92

Page 93: Text programming guide for iOS

+ (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

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

93

Page 94: Text programming guide for iOS

Inserting and Deleting TextA text view that adopts the UITextInput protocol must also adopt the UIKeyInput protocol. That meansit must implement the insertText:, deleteBackward, and hasText methods as discussed in “Simple TextInput” (page 85). Because the EditableCoreTextView class is adopting UITextInput, it must also maintainthe selected and marked text ranges (that is, the current values of the selectedTextRange andmarkedTextRange properties) as text is entered and deleted.

Listing 10-5 illustrates how EditableCoreTextView does this when text is entered. If there is marked textwhen a character is entered, it replaces the marked text with the character by calling thereplaceCharactersInRange:withString: method on the backing mutable string. If there is a selectedrange of text, it replaces the characters in that range with the input character. Otherwise, the method insertsthe 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;

}

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

94

Page 95: Text programming guide for iOS

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

Returning and Replacing Text by RangeAny text view that communicates with the text input system must, when requested, return a specified rangeof text and replace a range of text with a given string. The classes in our example, EditableCoreTextViewand SimpleCoreTextView, maintain synchronized copies of the backing string object(EditableCoreTextView as a NSMutableString object). The implementations of textInRange: andreplaceRange:withText: in Listing 10-6 call the appropriate NSString methods on the backing string toaccomplish 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;

}

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

95

Page 96: Text programming guide for iOS

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

Maintaining Selected and Marked Text RangesBecause editing operations are performed on selected and marked text, the text input system frequentlyrequests that the text view return and set the ranges of selected and marked text. Listing 10-7 shows howEditableCoreTextView returns the ranges of selected and marked text by implementing getter methodsfor 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 theembedded text view. The setMarkedText:selectedRange: method is more complex because, as you mayrecall, the range of marked text contains within it the range of selected text (even if the range merely identifiesthe 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;

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

96

Page 97: Text programming guide for iOS

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 thereplaceCharactersInRange:withString: method on its mutable string object, which it then assigns tothe text property of the embedded text view.

Frequently Called UITextInput MethodsWhen 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 themore 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 that’s a givenoffset from another position. Listing 10-9 shows how EditableCoreTextView implements this method(which includes range checking).

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

97

Page 98: Text programming guide for iOS

Listing 10-9 Implementing positionFromPosition:offset:

- (UITextPosition *)positionFromPosition:(UITextPosition *)positionoffset:(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 valuespecifying the offset between two text positions. EditableCoreTextView implements it as shown in Listing10-10.

Listing10-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.

Listing10-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];

}

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

98

Page 99: Text programming guide for iOS

Returning RectanglesWhen a correction bubble appears and when the user types in Japanese, the text input system sendsfirstRectForRange: andcaretRectForPosition: to the text view. The purpose of both of these methodsis to return a rectangle enclosing either a range of text or the caret that marks the insertion point. TheEditableCoreTextView class implements the first of these methods by calling a method of its embeddedtext view that maps the range to an enclosing rectangle (see Listing 10-12). Before returning the rectangle, itconverts it to the local coordinate system.

Listing10-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 lion’s share of the work. Using Core Text functions, itcomputes the rectangle that encloses the range of text and returns it, as shown in Listing 10-13.

Listing10-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;

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

99

Page 100: Text programming guide for iOS

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 ofthe caret rectangle can be different from the bounding rectangle returned from firstRectForRange:.

Hit TestingAnother area where the text input system asks the text view to map between the display of text and the storageof text is hit testing. Given a point in the text view (the text input system asks), what is the corresponding textposition or text range? TheUITextInputmethods it calls for this information areclosestPositionToPoint:,closestPositionToPoint:withinRange:, and characterRangeAtPoint:. Listing 10-14 illustrates howEditableCoreTextView implements the first of these methods.

Listing10-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, EditableCoreTextViewcalls a method of its embedded view that uses Core Text to calculate the character index that corresponds tothe point. Listing 10-15 illustrates how the embedded view accomplishes this.

Listing10-15

Mapping a point to a character index

- (NSInteger)closestIndexToPoint:(CGPoint)point {

NSArray *lines = (NSArray *) CTFrameGetLines(_frame);

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

100

Page 101: Text programming guide for iOS

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 ChangesWhen there is a change in text or a change in selection that is not initiated by the text input system, you shouldinform 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 theclass adopting the UITextInput protocol defines an inputDelegate property, the text input systemautomatically 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 tappedbut it isn’t the first responder, the text view makes itself the first responder and starts an editing session. If theview is subsequently tapped, the text view sends a selectionWillChange: message to the text inputdelegate. It then clears any marked text range and resets the selected text range so that the caret is at thepoint in the text where the tapped occurred. After this, it calls selectionDidChange:.

Listing10-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];

Lower Level Text-Handling TechnologiesCommunicating with the Text Input System

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

101

Page 102: Text programming guide for iOS

NSInteger index = [_textView closestIndexToPoint:[taplocationInView:_textView]];

_textView.markedTextRange = NSMakeRange(NSNotFound, 0);

_textView.selectedTextRange = NSMakeRange(index, 0);

[self.inputDelegate selectionDidChange:self];

}

}

Spell Checking and Word CompletionWith an instance of the UITextChecker class, you can check the spelling of a document or offer suggestionsfor completing partially entered words. When spell-checking a document, a UITextChecker object searchesa document at a specified offset. When it detects a misspelled word, it can also return an array of possiblecorrect spellings, ranked in the order which they should be presented to the user (that is, the most likelyreplacement word comes first). You typically use a single instance of UITextChecker per document, althoughyou can use a single instance to spell-check related pieces of text if you want to share ignored words and otherstate.

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 andimplementing the subclasses described in “Communicating with the Text Input System” (page 86).

The method you use for checking a document for misspelled words israngeOfMisspelledWordInString:range:startingAt:wrap:language:; the method used for obtainingthe list of possible replacement words is guessesForWordRange:inString:language:. You call thesemethods in the given order. To check an entire document, you call the two methods in a loop, resetting thestarting offset to the character following the corrected word at each cycle through the loop, as shown in Listing10-17.

Listing10-17

Spell-checking a document

- (IBAction)spellCheckDocument:(id)sender {

NSInteger currentOffset = 0;

NSRange currentRange = NSMakeRange(0, 0);

Lower Level Text-Handling TechnologiesSpell Checking and Word Completion

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

102

Page 103: Text programming guide for iOS

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:theTextrange: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 ofjust logging the misspelled words and their possible replacements, as the method in Listing 10-17 does, youshould display some user interface that allows users to select correct spellings, tell the text checker to ignoreor learn a word, and proceed to the next word without making any changes. One possible approach for aniPad app would be to use a popover view that lists the guesses in a table view and includes buttons such asReplace, Learn, Ignore, and so on.

You may also useUITextChecker to obtain completions for partially entered words and display the completionsin a table view in a popover view. For this task, you call thecompletionsForPartialWordRange:inString:language: method, passing in the range in the given

Lower Level Text-Handling TechnologiesSpell Checking and Word Completion

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

103

Page 104: Text programming guide for iOS

string to check. This method returns an array of possible words that complete the partially entered word. Listing10-18 shows how you might call this method and display a table view listing the completions in a popoverview.

Listing10-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 = [textCheckercompletionsForPartialWordRange: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];

}

Lower Level Text-Handling TechnologiesSpell Checking and Word Completion

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

104

Page 105: Text programming guide for iOS

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

NotesDate

Revised introduction figure. Fixed typos.2013-10-22

Added material describing Text Kit and typographical concepts and madeassociated changes throughout. Changed name from "Text, Web, andEditing Programming Guide for iOS".

2013-09-18

Updated information on pasteboard persistence and keyboard adjustment.Also made many small corrections.

2011-03-07

Made some minor corrections.2011-01-10

Added "Playing Input Clicks" to the "Custom Views for Data Input" chapter.2010-11-15

Incorporates information on copy-cut-paste operations, edit menumanagement, and custom data-input views. Made some minor correctionsand clarifications, especially with keyboard management. Title changedfrom "Text and Web Programming Guide for iOS".

Changed the title from "Text and Web Programming Guide for iPhoneOS."

2010-07-07

First version of a document that describes the technologies and techniquesfor displaying and managing text and web content in iOS.

2010-05-11

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

105

Document Revision History

Page 106: Text programming guide for iOS

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 anyform or by any means, mechanical, electronic,photocopying, recording, or otherwise, withoutprior written permission of Apple Inc., with thefollowing exceptions: Any person is herebyauthorized to store documentation on a singlecomputer for personal use only and to printcopies of documentation for personal useprovided that the documentation containsApple’s copyright notice.

No licenses, express or implied, are granted withrespect to any of the technology described in thisdocument. Apple retains all intellectual propertyrights associated with the technology describedin this document. This document is intended toassist application developers to developapplications only for Apple-labeled computers.

Apple Inc.1 Infinite LoopCupertino, CA 95014408-996-1010

Apple, the Apple logo, iPad, iPhone, OS X, Quartz,Safari, TrueType, and Xcode are trademarks ofApple Inc., registered in the U.S. and othercountries.

Helvetica and Times are registered trademarks ofHeidelberger Druckmaschinen AG, available fromLinotype Library GmbH.

Java is a registered trademark of Oracle and/orits affiliates.

iOS is a trademark or registered trademark ofCisco in the U.S. and other countries and is usedunder license.

Even though Apple has reviewed this document,APPLE MAKES NO WARRANTY OR REPRESENTATION,EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THISDOCUMENT, ITS QUALITY, ACCURACY,MERCHANTABILITY, OR FITNESS FOR A PARTICULARPURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED“AS IS,” AND YOU, THE READER, ARE ASSUMING THEENTIRE RISK AS TO ITS QUALITY AND ACCURACY.

IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIALDAMAGES RESULTING FROM ANY DEFECT ORINACCURACY IN THIS DOCUMENT, even if advised ofthe possibility of such damages.

THE WARRANTY AND REMEDIES SET FORTH ABOVEARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORALOR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer,agent, or employee is authorized to make anymodification, extension, or addition to this warranty.

Some states do not allow the exclusion or limitationof implied warranties or liability for incidental orconsequential damages, so the above limitation orexclusion may not apply to you. This warranty givesyou specific legal rights, and you may also have otherrights which vary from state to state.