Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2012-222
$eventId
ID of event: wwdc2012
$eventContentId
ID of session without event part: 222
$eventShortId
Shortened ID of event: wwdc12
$year
Year of session: 2012
$extension
Extension of original filename: mp4
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2012] [Session 222] Introductio...

WWDC12 • Session 222

Introduction to Attributed Strings for iOS

Essentials • iOS • 50:41

Text is an essential part of your application's interface. Get an introduction to the concepts behind manipulating and drawing attributed strings on iOS. Learn how UIKit has adopted attributed strings to make creating text effects even easier.

Speakers: Ian Baird, Johannes Fortmann, Aki Inoue

Unlisted on Apple Developer site

Downloads from Apple

SD Video (105.6 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good afternoon. This is session 222, Introduction to Attributed Strings for iOS. I'm Aki Inoue from the Cocoa Group. For the last couple of years, we've been getting numerous feedbacks requesting multi-style string drawing in iOS, much like Attributed String Integration on OS X. As Chris announced yesterday, spectacularly, in his What's New in Cocoa Touch session, the wait is over.

We are introducing UIKit and SFS string integration in iOS 6. These are the items we're covering today. First, I'm going to start with Attribute Essentials. How to create, how to modify, and how to work with them effortlessly and efficiently. So with this material, you should be able to bootstrap and work with the attributed string right away.

And I believe the materials present here should be valuable even for those of you who are already familiar with attributed string via core text. Then we're going to see some of the drawing attributes UIKit provides. Later on, you'll see how these new capabilities are integrated into the UIKit control classes. Let's get started.

When you go to iOS 6, when you wanted to render a string like this, you'd use ULLabel or your string drawing API. The data model for this functionality is based on NSString. When you want to render text, you specify a font, you specify a string, along with other required information. For example, you specify a string and a font. and the bold form, string, font, color. And there was no object bindings attributes together. and the attribute string. The object associates these attributes to the characters.

So you can attach font to your string object. You can specify a color to a range, or even specify various fonts to different ranges. So what can you exactly do with these attributed string objects? The first advantage is, of course, you can create multi-style attributed string. You can render and measure text, multi-style text as a single unit. This is from Stock's application.

As you see in the news section, it shows both headline and summary. The both string is the headline. When it requires more than one line, it wraps to the second line. Then the summary string in regular typeface is concatenated right after it. It's very easy. Another advantage is coming from the ability to attach an arbitrary number of attributes.

and That way we can extend the capability without complicating the API much so that we provide much more expressive options in terms of text formatting via attracing API. This is an example from Reminders. In order to reserve the space for priority icon, we are shifting the first line. You know, like this, you still require you to manually measure lines and render them separately. Now it's as easy as creating an attribute string with indent option and render.

Also, we're now more expressive in terms of graphics representation. Shadow, outline, underline, so on and so forth. This is rendered entirely using UIKit attributes. You don't have to go down to and Koi Graphics and more. You can have this kind of text effects right from the comfort from your UIKit object-oriented programming. What's an Assertive Stream? An Assertive Stream is not new, actually. In fact, it's been available in the foundation framework since iOS 3.2.

It's not just been used by UIKit up until now. And these two base methods represent the model object for the-- the data model for the attribution object. It has an string and a dictionary of attributes per character. And this is the designate initializer for the object. In it with string attributes, it takes a string and attributes.

The attributes are specified to the entire string this way. So let's create an attribute string. We're using NSFontAttributeName, an attribute key for specifying UI font to your string here. It's new for iOS 6. And using the initWithString attributes, we are creating a string with the system font at 12-point size here. Very easy.

One thing to note here is that AttributeString associates attributes to characters. So for an empty string, there's no attributes associated with it. This is an important characteristic of AttributeString, so I'm going to revisit the fact later in this talk again. So now you created an attribute string, let's modify it. Just like other foundation-date objects, this attribute string has clear separation between mutable and immutable classes. In this mutable attribute string, Mutable subclass of NSFH string has these two groups of mutable methods for changing attributes and changing string contents. Let's change the attributes first.

This is the best method for changing attributes. Set attributes range. It replaces the attributes at the range with the specified attributes. Straightforward. However, you typically work with these convenient methods for adding and removing attributes. This way, you can focus to a particular attribute. For example, if you have font picker UI, the object can focus to NSFont attribute name. And similarly, if you have color picker UI, you can focus to the text color attributes, so on and so forth.

So these methods are useful for modifying existing attributes, of course, but it's also useful for you creating the multi-style attributes. You might think when creating multi-style attribute string, You might consider instantiating an attribute string, plus I run and concatenate together at the end. However, it's much more efficient to instantiate the entire string up from the modified attributes as necessary. Let's create multi-style attribute string efficiently. Here we're using another attribute new to iOS 6 and it's program color attribute name for specifying text color using UAColor.

and we're instantiating attribute string using attribute string attributes but in this case we are instantiating NSMutable attribute string so that later you can modify the contents freely. And here, we're using add attribute value range to specify the red color to the time string. Here, now you have multi-saggible string. Now, change the string contents.

This is, again, the best method for changing the string contents for attributed string, replace characters in range with string. Just like there, just like its attribute counterpart, we have a convenient method for adding, replacing, and inserting attributed string. But I recommend to stick with the base replace characters in range with string method, because this way you can avoid instantiate temporary attribute string just for modifying your string contents. So let's work with the reproductive range with string here.

Here's an example. We have the same new robot you were seeing from the previous example. We want to move the dentist appointment one earlier at 8:15. Using replaced characters in range with string method. We accomplished that. Notice that we just specify a string here, yet the attribute is still there. Why is that? Because the attributes are preserved while you are working with the string contents. That way... Thank you.

That way, you are still-- when you are working with string contents, you can focus to the string contents and forget about attributes. In order to do so, you can just remember three simple rules. First, when you're replacing a range of text, the attributes for the new string is coming from the first character of the old range.

When you're inserting, the attributes coming from the previous character, and when you're inserting at the beginning, you don't have the previous character, so you have the attribute from index zero. Now, remember, I mentioned no character, no attribute rule. Because the attributes are associated with characters, when there's no attributes, there's no attributes to be inherited to a new string inserted. So with this characteristic, you might get surprised sometimes. You might want to be careful about this.

In this example, we are inserting a string at rotation three. Using the rule 2, the attributes coming from the previous character, the lowercase c, And with this example, inserting at the beginning, we're getting attribute index 0, the lowercase a, And also, when you are replacing a range of characters, you're getting the attribute from the first character from the old range, so lower Tc gives the attributes a new string. Finally, when you erase the entire string, there's no attribute anymore. So when you insert a new string, there's still no attributes. So you want to remember this fact.

[Transcript missing]

Let's work with attributes inside AttributeString. Internet attributes Using attributes at index effective range method, it returns an NSDictionary of attributes at specified location. Notice that the method takes another argument, a pointer to an NSRange. Upon returning from this method, it's filled with the concept of a range for the style run at the location. So it's useful when you want to identify the style run you are working with. But one thing to note here is that it doesn't return the maximum range possible. Because the way API is designed to be effective, it can return the date range readily available.

[Transcript missing]

The range argument could be filled at index 3 and length 3. However, it's possible to get shorter range, or even just the character itself. So if you want to work with the attributes sequentially, and Qualus, the operation on style rams, you can use these convenience method.

Attributes at index longest effective range and range and attributes at index longest effective range and range. This method takes extra effort to ensure the range you get is the maximum continuous range for the start run. So when you access string like this, with attributes that index from this effective range in range, you get the full style runs as expected.

Similarly, if you use attribute at index, longest effective range in range with NS1 attribute name, you get two ranges. Similarly, if you use NSProgramColorAttributeName, as you expected, three ranges. Very simple. So if you want to work with attributes sequentially, process, style run one by one, you can use this attribute animation method. It takes a block and the block is invoked per style run.

So it's useful when you want to change the attributes based on existing attributes. For example, if you want to change the font attribute from the regular typeface to bold typeface, it's very useful. Similarly, it's useful for when you want to change the string contents while preserving the multi-style configuration.

How do you do that? In this example, we are advertising the entire string that has multiple styles, and you want to preserve the styles there. To do so, first, we're going to get the current locale because the appartage operation is locale sensitive operation. Then we're going to call animate attributes and range options using block.

Instead of block, we create a substring using the specified range and replace the characters. And here, using the upper case, AppletasteString with locale, specifying the locale to do the proper locale-sensitive operation. And the result is AppletasteString, while the attributes are still preserved. Now you're familiar with the attributes string. Let's take a look at some of the drawing attributes we introduce in iOS 6.

This is an example string from the previous section. Once you have an attributed string like this, rendering is very easy. Just send the message, draw a point. That's it. In iOS 6, we're introducing NSStringDrawing API from UIKit. It's much like the NSRT string categories found in OS X. The method has two major groups, one simple, one extended. In the simple drawing method, we have drawing rect, draw point, size, very simple interface. Yet, because of the abilities we are providing through attributes, they can perform pretty sophisticated tasks here.

Drawing reg renders itself inside a specified reg. And depending on the setting inside that string itself, it can wrap or truncate itself properly. and DrawAtPoint can render itself at a specified point. And since there's no constraint size specified here, it just renders as a single line mode. Similarly, the size method does the single line measurement of the receiver. and these are pretty much a giver and their counterpart in US String Drawing API. DrawingRef is very similar to DrawingRef with font, line break mode, alignment. And DrawedPoint, similar to DrawedPoint with font, size method with size with font.

and we are introducing a slew of attributes you can use in iOS 6. You have many bells and whistles for configuring the appearance of layout of your attribute strings inside the applications. Here, I'm focusing to three of the basic attributes you're going to be commonly using again and again.

You've already seen the first two NSFont attribute name and NSForegroundColor attribute name. and the third one is an NSParagraph attribute name that controls the text formatting options. Each of these attributes uses UI font, UI color and NSParagraph style object as its value.

[Transcript missing]

An attribute missing from attribute dictionary means that's implying the default value, not just unspecified. What does that mean?

Instead of just leaving the attribute unspecified, we use the default value for each attribute if they are missing from the attribute dictionary. For example, for the font attributes, we use the system font of system font size and the black color for text color, and similarly default paragraph style for the paragraph style attribute.

Here is an example illustrating the default value usage. Because since there is no unspecified attributes in AttributeString, the attribute string can always produce an expected result for you. For example, you have an attribute string here, this time using initWithString method. It's a convenience cover for the initializer. And this method does take any attribute. So the attribute is essentially empty for this attribute string.

Now, we are rendering, we are filling the background with red color. What this means is the CG content color property is left with a red color setting. Now, we render with the empty attributes. The end result is instead of using the CGColorColor property, we are using the default value, black color, to render here.

Now let's take a look at the final attribute in this session in the form of style attribute name. And this part of the style encapsulates various paragraphs-wide text formatting options for you. Line Break Mode, Alignment, Line Spacing, so on and so forth. They give you powerful text formatting capability to your applications. And because of that, you can have rich word processor-like text formatting in your application.

And notice that the single paragraph style object is shared for an entire paragraph. Because the way attributed string works, you can apply and assign multiple paragraph style objects to a string, but only the first attribute, the first one associated with the first character in the paragraph is used for the entire paragraph style. and this is an example we showed early in this session from reminders. It's using the indenting option using Power Star to reserve the space for the priority icon.

We have this setting in Paragraph style, line break mode, alignment, spacing for lines, between lines and between paragraphs. indentation. You can control margin from left to right and for the first line specifically. And you can have final control over line height. and finally, you can control hyphenation and right to left settings using the power of style. We're going to see two of the commonly used Firehose style settings here.

First, line break mode. It's very similar to UI line break mode you are familiar with. First, you We are creating mutable paragraph style just like other objects. The NSParagraphStyle has separation of mutable and immutable classes. Here we're using NSMutableParagraphStyle. The init method returns the paragraph instance configure for the system default.

So that all you have to do is just change the setting you want to customize here. Here, you are changing line break mode to tail-translation. And using this paragraph style, the end result is tail-translated text. Alignment. Very similar to UI text alignment, you can specify left, center, right alignment as expected. In addition to that, we are providing full justification.

And finally, you can specify a natural alignment. What does this mean is that When you specify this setting, for majority of all languages, the text is left online, but if you are working with write to left language such as Arabic or Hebrew. It's going to be automatically write a line.

usually have an appetite for more rendering power. We have advanced attributed string sessions. We're going to show more bell and whistle for treating your application's attributed string. So it's good to come back for this session if you want to do these tricks. Now I'd like to switch over to my colleague from UIKit group, Ian Baird, who's going to show how these new capabilities are integrated into UIKit controls. Ian.

Thank you, Akki. Hi, I'm Ian Baird. I'm a label engineer for UIKit, and I'm happy to talk to you about UIKit's adoption of attributed strings. or how do I get this stuff into my labels? The first thing to remember is that UILabel is really your nexus of power.

If you understand how to use attributed text with UILabel, you essentially understand how to use attributed strings with the rest of UIKit. This is a UI label with a title. It says, hi, I'm a UI label with a title. And you can see it's unadorned. We've used thousands if not millions of these in our apps. I'd like to introduce to you today UI label with an attributed title.

There are a few existing properties on UILabel that you've probably used before. The first one is the text property. This takes an NSString instance and it tells the label what you want it to represent. The next property is the font property. As you see, we've changed from the system to font, in this case, Helvetica Noia, to one of my favorites, Heuveler Text.

Next, you can change the text color by supplying a UI color instance to the text color attribute. You can even change the text alignment as we have done here, changing the text alignment from center aligned to left aligned using the text alignment property You can set up word wrapping using line break mode. You can add a shadow with shadow color. And you can change the shadow offset.

We've added a new property to this, attributed text. As you can see, now you can supply an NS attributed string to UILabel and it will represent your attributed string as we have done here. We've also added a new property, minimum scale factor. This tells Label exactly how small it can shrink all of your fonts before we'll begin to truncate the text to try to fit it within the bounds of the label.

We also added a new Boolean property, adjust letter spacing to fit width. This tells us exactly how much -- it tells us exactly -- sorry. It tells us we can adjust the tracking between your characters to try to fit all of the text in the UI label's bounds.

We've deprecated a property. Minimum font size. In a new world where you can have multiple fonts and multiple font point sizes, it no longer makes sense to specify a minimum font size. We would prefer that you instead use the new minimum scale factor property. There are a few things to remember when using labels and attributed strings. And this is one of the most important. When you're using any of the existing style properties, the properties are going to apply the style to the entire string.

So for example, if I set the font with the font property, NS font attribute name is going to be set to Helvetica Noi for the entire string. Next, if I change the text color using the text color property, you're going to change the text color for the entire attributed string.

and that's Label. Next today, I'd like to tell you about what we've done with Button by building on the methods you already know. First, the setTitleForControlState method allows you to supply, again, an NSString for a certain control state for the button. This will render the NSString on the face of the button.

knew in iOS 6, set attributed title for control state allows you to supply an NS attributed string for a UI control state. And an important point to remember is that this new attributed title is going to take precedence. If you set title for UI control state normal and set attributed title for UI control state normal, the button is going to show the attributed title. We've even changed Pickerview to Pickerview Caliente.

To achieve this effect, just implement PickerView attributed title for row for component in your UI PickerView data source. We've added some properties to UI TextView. The first one is attributed text. You can supply an attributed string to UI TextView and it's going to render the string as its content. Next, we've added a Boolean property allows editing text attributes.

We're excited about it, too. It allows your users to interact with and change any of the style properties in the text view on the attributed string. You can then fetch this attributed string back out via the property. Any new update to the API of UIKit, any talk about new updates to UIKit is really incomplete without a discussion of TableView.

TableView, as Chris said, is really the workhorse of UIKit. And today I'm happy to tell you there are no new properties or methods. just set attributed text on the cell or header views text label. has prepared a demo and he's going to show you all this cool new functionality in UIKit.

Thanks, Ian. Hi, I'm Johannes Fortmann from the UIKit team, and I've prepared a little application that shows you how to use these attributed strings in your app to render beautiful text. My application is basically very simple. I have a few pages from speeches from famous plays and I render them. You might use that on the bus to learn your text if you're an actor, for example, or just to look at the beautiful typography. Let me show you how that looks right now.

I'm switching to demo here. I'm going to run this for you so you can see how it looks. And here we go. As you can see, we have a beautiful collection view, our new class here, and we are showing several pages from speeches like Midsummer Night's Dream. And when you tap one of these, you can see a nice, though unstyled rendering of these.

And you can see the text here. And you can So what I want to do first here is transform my app, which has been written against the old version of the OS, apparently, to use the new amazing features we have. I've already put in a method to compare and contrast these.

So if I slide here, we see nothing, because I didn't actually implement the rendering. It should be -- it should switch between these two rendering modes. So let's look at the implementation of this. Looking at the implementation here, we have a page view and this page view renders pages paragraph by paragraph.

So what we're doing here is basically our data model has these pages laid out and separated in paragraphs. We are going, walking through the page one paragraph at a time, drawing it, and sizing it up. We also have a case distinction here. If we're using unstyled drawing, we are just using the old rendering path and the style drawing, well, it's implemented with a copy here. That's obviously no good. So I'm going to delete this.

So first, if we want to render an attributed string, we need to get an attributed string. I've already implemented a method on my data model to actually format the string. And I'm going to call it to get my string, which I will then later render. Then because we have to advance our page cursor down our page, we have to size up our string. I'm going to do that. And then finally we have to actually draw it. That's it. That's how easy this is. Let's have a look at this.

All right. So, this is our new rendering, and I'm zooming in here so you can actually see that we are rendering with attributes because this is kind of tiny on the big screen. You see how we are beautifully rendering in two different fonts. And if I use my switch gesture, please pay attention to the will here because that's going to change.

I'm switching back to the simple rendering now. And as you can see, the simple rendering, unlike the new attributed rendering, doesn't support attributes like the kerning attribute. So, we don't actually kern in the simple rendering, whereas we do proper kerning with the attributed rendering system, which allows us to render this much more beautifully.

All right. Let's switch back to this overview here. And as you can see here, our title of our page is using a UI label. And right now we are basically using the standard UI label, we are setting the title, and we are setting the text color. But we're not making use of the new attributes here.

So let's change that by bringing this label into the new exciting world of attributed strings. I'm going to pull up my page preview cell. As you know, the collection view uses cells to render each of these objects we see here. And this is the cell we are using.

Basically what we're doing right now is what I just said. We have a text label, set its text to the title of our page, and then we're setting the color. Now we won't need this anymore, so I can delete it. And what we actually need to do now here is we want to create an attributed string. What we have to do is first we have to create a style dictionary which defines the style of our attributed string.

I'm going to do that. I'm choosing to leave the font name empty so we use the default font as we did before. We didn't set a font on the label. I'm only setting the foreground color to be a red color. Just like before. Okay. Then we have to create the attributed string here. That's a simple call to the method. We have to init with the old string, page title, and use the attributes to set on this string. And finally, I have to assign it to my label. That's it. Let's look at this.

Well, that was boring. We didn't change anything. It looks exactly the same. But we can see here that at least we've verified that our attributed string rendering works exactly like it did before with the non-attributed rendering. Let's go back and spice this up a little. You can see we've -- in our labels, we have basically always the name of the play and then the name of a scene within this play. What I want to do now is kind of emphasize the name of the scene here. So I want to set a different font, a bold font. Let's do that.

I've already created a mutable attributed string so I can now change the attributes on our attributed string. And to change the attributes on part of the string, what I have to do is first actually find the separator that divides our name of the play from the name of the scene. That's a hyphen in this case. So I'm going to find this hyphen. Oh, first I'm going to, of course, create the font I want to later set.

Then I'm going to find my hyphen. That's just a call to range of string. Now I have to move my range that I just created to just after the hyphen because we don't want the hyphen to actually be bold. And finally, I have to extend the range to the full extent of my scene name. So let me do that.

The last thing I have to do is actually set my new bold font on this range, this range only, of course. So I'm doing that. Let's have another look at the current appearance of this. All right. I'm going to zoom in here so we can actually see that this is bold. And it's a very nice bold. It's understated and tasteful, yet kind of beautiful.

All right. Let's have a look at the page view again. Now, you see here we have these stage directions. I'm going to show you with the mouse here. It's the Oberon leading the fairy sing and dance here, for example. And these are kind of indented. I did that with a few spaces. It's not as good as it could be.

And, well, it's also black like the rest of the text. So, people might actually accidentally read this. So, what I want to do now is change these stage directions to be first making use of the NS paragraph style attribute centered and second to have a slightly different color and better font. So, let's do that. And here I'm going to show you how I'm formatting these strings.

I do that in my data model in the attributed string for paragraph method which I'm pulling up now. And this is really very simple. What we're doing here is we get the speaker for the current paragraph, we get the text, and then we create an attributed string for the speaker and an attributed string for the text.

Finally, we append those. So, and then we return the value for current paragraph. Now, you can see here that the string is not the same as the previous string. You can see here the attributes we are using are attributes that are apparently instance variables here which are already predefined. That's a good idea because we don't want to create a new dictionary every time we format a simple paragraph. So, let's look at where we define that. And I'm doing that in my designated initializer here. In the knit with title method. That's my pages initializer. together.

You can see here I'm creating the speaker attributes with my speaker color and bold font and I'm creating the text attributes with the text color and, well, the regular font here. and now I want to create my stage direction attributes. Now, as I said, I want these to be centered. So I have to create a NS paragraph style. In fact, an NSMutable paragraph style. I'm going to create that one.

That's my centered style. It's the default style, only it's mutable. And now I have to actually set its alignment to be actually centered. That's this line where I just set the alignment. I also have to create a font that's for this paragraph style I chose to use an italic font that's a bit lighter. That's the and Helvetica Light Oblique font. Now, having created that, all that remains for me to do for this is to actually create the style dictionary and stow it away into my instance variable.

All right. Now that we have initialized our style dictionary, I'm going back to the attributed string method. And now I can format my paragraph. Of course, I only want to format it if it's actually stage direction. Otherwise, the current formatting is fine. So I'm distinguishing the two cases. This one here is if the paragraph is a stage direction. And the other one is my old one, old case. Let me reformat that quickly. That's the case where we format as usual.

Okay, in the stage direction case, all that remains for me to do is actually format the text with my new paragraph style and, well, append it to my return value. Let me run that for you. and here we go. Let me zoom in. And now my paragraph is actually centered and the font is changed and the color too. All right. Let me switch back to slides.

So to sum this up, you've seen how to actually draw text using the attributed string methods. You've seen how easy it is to enhance an existing label. So you have a label which is pretty common case. And you want to spruce it up just a little by adding extended attributes. And finally, you have seen how to use paragraph styles. And with that, I give back to Ian.

Thank you, Johannes. So you've seen a lot of things today. You've seen the basics of using, creating, modifying, and querying attributed strings. You've seen how to do this. Akki took you on a whirlwind tour of the API. Next, you saw how to draw them and use them with paragraph styles. And finally, we showed you how they were adopted by UIKit.

If you'd like to know more, I'd recommend contacting our UI Frameworks evangelist, Jake Behrens. He'll be happy to help guide you in your quest for more information about attributed strings and their use with UIKit. Next, you can also visit the UIKit documentation online. And finally, if you haven't visited the Apple Developer Forums, I would urge you to. It's a great place to go to give and receive peer-to-peer support and interact with employees like Akki, Johannes, and myself.

Next, we have a few related sessions. As Akki talked about earlier, we have our advanced attributed strings for iOS talk. You're going to learn about shadow attribute, stroke attribute, and a host of other attributes that we talked about today but didn't go into depth for. Next, you should catch the video for keyboard input in iOS.

They're going to talk more about UI Text Field, UI Text View, and their adoption of attributed string. Finally, there's going to be a session on core text and fonts. Core text is the awesome, awesome framework which underlies all of this new technology. So I would urge you to go and see this session.