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-220
$eventId
ID of event: wwdc2012
$eventContentId
ID of session without event part: 220
$eventShortId
Shortened ID of event: wwdc12
$year
Year of session: 2012
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2012] [Session 220] Keyboard In...

WWDC12 • Session 220

Keyboard Input in iOS

Essentials • iOS • 29:23

Learn how to leverage what's new in iOS to improve the onscreen keyboard and text editing experience for your users. Make your app shine for users around the world with support for Asian languages, split and undocked keyboard interaction, rich text editing, and more.

Speakers: Justin Garcia, Morgan Winer

Unlisted on Apple Developer site

Downloads from Apple

HD Video (236.9 MB)

Transcript

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

Now, I know that a lot of you guys are brand new to iOS development. That's totally fine. Keyboard Input Basics are really, really easy to implement. A lot of you guys have written apps before, so for you, some of this will be a refresher, but we do have some brand new features to show you.

And then I think that there are a lot of guys out there, some of them sitting in the front row, that could probably get up here and do this presentation for me. You guys are writing your own custom text views, and for you, we have something brand new to show you about halfway through.

So let's get started. So I think that no matter what your experience level is, we're all here at WWDC today because we love making stuff. But as much fun as it is to do what you love, you've got to get paid. And this figure doesn't even include Instagram as a big payday.

So enormous potential in the App Store marketplace. But how do we tap into that? Well, history dictates pretty clearly what kind of app rating we need to be successful. So that's what we want to help you out with today. Obviously, you guys are creating the innovation, driving people to the app. But once they're there, nearly every app has a keyboard, even some games. So we think that we can help you with this.

So we're going to show you the basics and along the way show you the holes not to fall into and then we're going to bring the magic and show you some new iOS 6 stuff. Keyboard input can be broken into three parts: managing the keyboard itself, static text, and then handling live user input.

I think that you all know that the keyboard supports many different languages, but what you may not know is that it supports emoji for all users. We actually have some brand new emoji in iOS 6, like the dude here. We'll get back into what emoji means for you in a minute, but for now, we have four types of size and position changes that you need to be aware of. And then you need to know the right way to attach views to the keyboard.

So size and position changes. Bring up, of course, you have an enormous potential user base in Asia Pacific and Japan that use keyboards with a candidate bar. Our users love split and undock keyboards. And as good as our software keyboard is, a lot of people are using hardware keyboards.

So your users have come to expect from first party apps like Safari a smooth, fluid bring up experience on keyboard bring up. Here Safari fades the UI out and animates the Google search field to the left. They do this with three pieces of information. The animation duration, curve, and end frame for the keyboard.

Once they have these pieces of information, they can kick off their own animations to match keyboard bring up animation exactly. And they do this in response to UI keyboard will show. You pull this info out of the notification with the user info dictionary. You obtain the end frame. Now, all of the beginning and end frames that you'll see, remember, are in screen coordinates.

You get the animation curve with this key, duration with this key. Now you have what you need to know to kick off your own animation. When the animation is finished, keyboard's up, you might show an editing toolbar, scroll the cursor to visible. On the flip side, when the keyboard's coming down, you're going to use the exact same keys as we'll show.

and then we'll hide when the keyboard's finally hidden. Bring up. So again, enormous potential user base in Asia Pacific and Japan, but don't take it from me. Now, I think that some of you may never have seen the candidate bar before. This is what it is. I have a conversation with a friend from Japan, and I want to respond to her in Japanese, so I switch to the Japanese keyboard.

But in this hypothetical example, messages doesn't respond to the candidate bar, so this balloon is clipped. Fixing this is easy with two notifications: "will change frame" and "did change frame." In response to those notifications, you use these two keys: "begin" and "end frame" again. And remember screen coordinates. Now you can adjust your content.

Users love split and undocked keyboards. And this is what this means for you. This is what Safari does in response to the split keyboard. Let me show you a quick demo. So here I am in Safari. And I'm doing find home page on this apple.com page for support.

The content adjusts to take advantage of the increased space of the split keyboard offers. And then as I perform find on page, The highlighted rect always stays in the area above the split keyboard so that the split keyboard never occludes it. And that's it. So how did they do this? Well, there are three notifications that they leveraged to do this.

First, will hide when the keyboard is about to be split or undocked. Did hide. At this point, they adjust their content. And then as you move the split keyboard up and down the screen, you will receive will and did change frame notifications. And don't forget, split keyboards are shorter than their standard variants.

Now, again, as good as the software keyboard is, people love using hardware keyboards for iPad. Fortunately, responding to a hardware keyboard being plugged in or disconnected is exactly the same as dismissal. So that's size and position changes. Now, to demonstrate some of the concepts that we're talking about today, we've prepared a demo. This is called a text-based role-playing game.

On the right-hand side, you have the game story. It tells you where you are and lets you enter commands to interact with the game world. On the left, character status. The problem I have now is that the UI doesn't respond to keyboard split or docking. So what I want to do is adjust this border and the game story view. And it's really easy with what I just showed you.

So here's keyboard we'll show. And all you need is the keyboard frame. When the keyboard is being shown, all you need to know is its height since it's docked at the bottom. You get the animation curve, duration. Now, when the split keyboard is being docked, it will receive again, will show, but the animation is instantaneous. We still want an animation, so we change the duration to 0.25. And then we adjust our border frame. In our game text view. Really quick, we'll see what that's like.

There you go. So those are size and position changes. Now we need to talk about the right way to attach views to the keyboard. What we'd like is to move text entry from the game story view down to its own view that floats above the keyboard. You saw this on our app. This is what we want to change it to.

We also have some directional controls that we'll put in that view. How do we float this? Well, we've seen a lot of people try and do this manually. It's problematic. There's a really easy way to do this. just the input accessory view property on UI text field and UI text view. And really quickly, I'm going to show that. So most of this code is really straightforward. I'm just going to show you one thing. We have an invisible text view that we first make first responder.

This is because the text view has been moved to a view that lives inside the keyboard. So when the keyboard is down and you try to make that first responder, it's not in the view hierarchy and the keyboard doesn't come up. So we have an invisible text view that we create here. We make that first responder once the keyboard is up. Then we switch first responder status to the text view in the accessory view and we're good. So here it is. Coolio.

So that's everything for managing the keyboard. Now, static text. Now, you don't need to be a Unicode expert, but you do need to know some basics. Then we're going to unveil a brand-new feature for custom text views and show you how to leverage UI text input in standard text views. It's not just for custom text views.

So here I am in notes. I'm writing with the Chinese handwriting keyboard. And I want this second character here. So I pick it. But how do I pull this user-visible character out of the text view? You might think, well, character index 0, it's the first user-visible character. The problem here is that a character index 0 returns a Unicar, whereas this character requires four bytes in memory. And the same goes for emoji here. So this is what you'd see if you displayed that to the user.

Again, this character occupies four bytes in memory. Here's the character, its Unicode value. Here it is in memory. And again, if you interpreted it as two separate Unicars and displayed it to the user, this is what you'd get. Fortunately, fixing this is simple with a range of composed character sequence at index zero.

That obtains an NS range for the character. You obtain a string like this, and you're done. What if you have a whole series of user visible characters? Here we are in messages and we want to obtain a character count for this bubble. So we want to enumerate over all of these user visible characters and count them. We just use enumerate substrings in range options using block with the NSString enumeration by composed character sequences option. I'm going to pass this block to be performed on every user-visible character sequence. And that's it.

Just don't assume Unicar. You want to be thinking of a string as being composed of a series of composed character sequences. You saw enumeration by composed character sequences for enumeration by other textual units see Doug Davidson's talk on text and linguistic analysis that's going on this week. and for internationalization topics that touch on Unicode, specifically localizing your apps in other countries, internationalization tips and tricks. So we have a brand new feature, as I said, in iOS 6 for custom text views. And to introduce it, I'd like to bring up my colleague, Morgan WineR.

Morgan? Little better? All right. Thank you. So we're going to go through the UI Text Input Protocol today. So for those who have seen it before, we did put it into iOS 3.2, and we're going to upgrade it a little bit today in iOS 6. So, real quick, why would you want a custom text view? Well, we provide two text widgets with the system, UI Text View and UI Text Field, and we'd like to think that these take care of as many possibilities as they can, but they really can't handle everything.

That's up to you. You guys have your awesome apps, and you need some custom functionality that we really just can't account for. What would you want to do? You guys might want 3D text. You might want an equation editor. Or here in Coda, we have a syntax highlighting HTML editor.

So what's involved in this? Again, the UI Text Input protocol being a protocol, you can apply it to any UI responder, any UI view, and it'll turn that UI responder into a text widget that you can type into with the system keyboard, get auto corrections, so on and so forth.

And it can interact the way that UI Text View and UI Text Fill do. Real quick before we go on, there's also the opportunity with a custom UI Text Input protocol implementation to actually override the tokenizer. So there's a UI Text Input tokenizer class. We have a default implementation in it. And you can override it.

So why won't you do this? Well, tokenizers actually do the breakings between characters, words, lines, paragraphs, so on and so forth. And say perhaps for Germany you wanted to not have hyphens break a word. That's pretty reasonable. So you can customize that. Or maybe you want to change some other things. Just wanted to point out that you do have that ability.

So with the UI Text Input protocol, though, up until now, you don't get system selection. You don't get any selection. You have to implement your own caret. You have to implement your own magnifiers. And if you really just want it to act like the system, you have to reimplement all the things that we've already done. And that's a lot of work that you guys could put into making your app special.

So these are all the things that are covered by system selection. We've got the carrot. We've got the range paddles for the range selection. We've got, of course, the magnifiers and even the dictation placeholder dots. So now in iOS 6, we'd like to help you out with those.

So previously you would have subclassed UIView, most likely, possibly UIResponder if you wanted to implement a different display layer than your actual backend layer. So all you would ideally need to do is just change what you subclassed. That's the opt-in mechanism. Subclass UITextView rather than UIResponder or UIView. Now, you'll still have your own backend implementation behind that, but you'll be replacing the actual functionality that we put inside UITextView with your own.

However, that's not quite the whole story. Turns out the UI text input protocol wasn't quite ready for this, so we've upgraded it. There's new selectionRexForRange method. Now, the selectionRexForRange We'll get into it in more detail in a second, but essentially it's to handle range selections. We already had a caret rect for position method.

This is the equivalent for range selections. Also, don't forget, there's the UI text input delegate. So whenever you need to change the text or the selection, and the selection bit's important, please let us know. Call the will change before, call the did change after. That way we can have the system match what you need it to do. So the UI text input protocol needs to work with a couple of fundamental units in order to navigate a document. The first of which is UI text position. Now this is an abstract base class. You have to provide your own implementation of it.

But it doesn't specify any IVARs, doesn't specify any properties, methods, anything. It's pretty much just an empty encapsulation of a single position in a document such as a caret. And we make no assumptions about what it means for your text storage. It could mean whatever you choose. Doesn't even have to be unique. You could have two UI text positions that both correspond to the same position in the document. That's fine. But you do have to provide an implementation. So if you stick two UI text positions together, you get a UI text range.

Now the UI text range is an interesting little class, another abstract-based class that you'd have to fill in an implementation of. So here in the screenshot you see that there's multiple text directions. We have Arabic mixed with English. The selection you see here is actually a single UI text range.

So the interesting thing about this is that in that UI text range, the English text spans right into the Arabic text, and that's part of a single range, but they're laid out disjointedly on the screen. That's possible. has to be something that your document can do. Or perhaps you might want to draw Arabic text a different way, and that's fine, too.

But it does have to be something you have to be aware of. And one final note, UI text range can actually have the start position be the same as the end position, in which case that's kind of an empty selection, but we still treat that as a carrot. Just something to be aware of.

So now we have this new class, a new abstract base class, again, subclass it and fill in an implementation of UITextSelectionRect. And this, well, individually, I suppose you can work with it, but we ask for an array of them. Because a single UITextRange can be any number of UITextSelectionRects. And this is what you'll return. You'll return an array of them from that SelectionRects for range. We'll give you the UIRange we need. You'll give us back the rects.

So there's a couple of interesting things about this, too. Contains start and contains end. This is how we know where to put those little blue paddles. So please return yes once and only once for each of those. If you have 10 UI selection recs, please return yes once for a Canadian start and a Canadian send across the array of them.

Also note, that dinner plans line on the first row, it doesn't take up the whole row, but the selection does. Line wrapping. It is entirely up to you, but please make a decision and stick your implementation to it. Also, you'll note that between rows of text in this selection, there's no gaps.

And that's because we actually went out of our way to fill in the line spacing with the selection reqs. Again, that is something we're leaving entirely up to you with your text selection reqs. Just something to be aware of. And then finally, yes, they're fairly cheap views to have, but they're not free. So if you can find a way to union them together just so that we don't end up with a million of them for a single selection, that would be good.

And then finally, the dictation thinking dots, these little purple dots that show up when dictation is taking its time to translate your voice into text. That's part of the selection system. So you can get this now, too. There's these three optional methods. You can choose to skip them if you'd like. Insert dictation result placeholder.

So we're going to ask for a placeholder from your text widget. It's an ID and NSObject. Again, we make no assumption what that means for your internal storage. We will ask for the frame of it, though. And this is how you pick the size of those dots. If you want to scale it to your text height, that's fine. You might want to just use a UI text position.

The text position would actually be a fairly ideal thing to return, but again, we'd make no assumptions. And then when we're done with the dictation placeholder, we'll pass it back to you, let you know whether the user canceled dictation or has some text coming, and then you can clean it up. So let's take a look at this. So right here, I have a very simple text implementation. It's a subclass of UIView. It's very, very, very simple. There's a fixed amount of text. I've already preloaded it.

The keyboard comes up, but I can't really interact with the document. I don't have any gestures on it. I've just really subclassed UIView, no carets. And that's what we've had up to now. I do have an implementation for selectionRex for range. So I'm just going to change this to be a subclass of UITextView.

Build and run that. Hey, I've got a carrot. Let me hold down, drag it around. I double clicked there and it filled out the selection to contain the entire word. That works too. So, give it a shot. Let us know what you think. And please, of course, file bugs if you have any problems. And that's system selection in iOS 6.

So Morgan talked about UI text input in custom text views, but you can also leverage it in standard text views. This is VoiceOver's screen reader reading paragraphs at a time, and it implements a paragraph at point with UI text input. This is iBooks doing word-by-word highlighting and it implements Word at Point using UI text input.

How does this work? Well, I've written a range for a word at point that takes in a point P, and you obtain a UI text position with closest position to point, and then a range around the word with range and closing position with granularity in direction, with word granularity. And you want to use UI text layout direction forward here to get the next word at a word boundary instead of UI text layout direction right so your code works in right to left text.

And you're done. This is an auto correction feature that we've had for a while. When you backspace, you get alternate suggestions for the previous word. Well, how do you get that previous word? Obtain the cursor position with selected text range. In the event that your selection is a range, just grab it, start, and then go to the previous word with position from position to boundary and direction. Again, using UI text storage direction backward here instead of left so that your code works in right to left text. And now you obtain a word range with those two positions with text from position to position.

and pull your string with text and range. And that's managing static text. Now user input. So for you new guys, text input traits are a really easy way to improve the text input experience. Then we have a brand new way to do rich text editing that's a lot easier than what we had before. And we have some dictation APIs.

Now, we have eight traits in total. I'm just going to show you the most important three. Now, keyboard type is usually pretty obvious. URL field here. Phone pad. This case is kind of interesting. This is username entry in the Apple ID sign-on sheet. And we use the email keyboard here because usernames are often email addresses.

Auto correction. When would you ever want to turn off auto correction? Again, user name field in the Apple ID sign-on sheet because usernames are often not real words. auto capitalization type. Context does a really good job of this. Word capitalization and character capitalization here. And those are traits and setting them is really easy in Xcode.

So that's traits. Now, to do rich text editing on the system before, you used to have to write a custom text view or use a UI web view in JavaScript, HTML, CSS. You don't have to do that anymore. It's really just -- So a couple things to this. Bold Italic and Underline controls, as you see here. multi-styled text with NS attributed string and typing style. Bold italic and underline controls, easy to implement with just a single property. Now let's add some multi-styled text to our game. We want to highlight important stuff.

So I'm just going to show you styling north, south, east, and west. And then we'll do an extended example in a minute. Actually, let's talk about NSAttributedString before we do this. I'm just going to show you the end result. So let's look around. All right. So we've got an imaginary friend Bill here who's going to help us kill this undead pirate. But before we do that, let's talk about NSAttributedString.

Styling these first two characters, or the third and fourth character green here, how does this work? We're going to create an NSMutable attribute string to make it easier to work with. And then we add the style. A style is composed of just three parts, the attribute key, the attribute value, and then the range that the style applies to. And we have some attributes for styles that you couldn't get previously, like highlight, text shadow, and underlining.

So I'm gonna throw some strikethrough onto this string like this. Now, strikethrough, to turn strikethrough on, use NSNumber number with bool yes. But we have a new shorthand with Objective-C literals that you may have seen for NSNumber that's just @yes. And you throw it in the text field like this. Rich text editing isn't the only thing using NS Attributed String. You've got NS Attributed String all over the system, buttons and labels. Here's reminders using it to do these priority glyphs.

Real quick typing attributes and then we'll jump back to the demo. This is a way to set typing styles. So what we want to have is the ability to color things in the text entry view after commands on the fly to match what's in the game story. So if I type kill, I want to turn on a red typing style.

This is super easy with typing attributes. You just get the typing attributes, add what you want, and then set it back. Typing attributes change as you change the selection to match the style of the current selection. So real quick, let's go back to the demo. And I'm going to turn on both typing attributes and multi-style text. And I want to get kind of pumped for this battle, so I'm going to throw on some battle tunes.

So, yeah, let's try to do this. So we swing and miss, and now we're... Yeah, that was kind of embarrassing. That wasn't supposed to happen. Let's go back to the slides. But you saw, real quick before we leave, you saw typing attributes. I type kill. I get kill pirate. If I want to say something, I get say hello. It's green. And that's it. Thanks a lot.

Wrapping up, we have dictation APIs. Your users love dictation, but what does that mean for you? Well, we have the ability to get dictation alternatives. Here's an idea. I mocked up a messages app that when you search, searches not just for dictation results but dictation alternatives. For instance, if I say "flower" and I get "flower" underlined, I get not just results for Flour, F-L-O-W-E-R, but also Flour, F-L-O-U-R.

So how do we do this? Just catch insert dictation result on your UI text field or UI text view subclass. Iterate over the result. It's a series of UI dictation phrases. Each dictation phrase is going to have zero more alternatives. And with those alternatives, you can build the entire set of interpretations for this result. So great documentation. Check it out. Come to the lab. Email Paul Marcus if you get stuck. Our application service is Evangelist.

Again, attributed string isn't just about rich text editing. It's all over the system. We have two sessions this week, internationalization tips and tricks for Unicode. So real quick and then you guys are out of here. Keyboard size and position changes, attaching views to the keyboard, Unicode basics, brand new way to do system selection easily in custom text views. UITextInput isn't just about custom text views. It applies to standard text views as well. There's some interesting ways to leverage it. You got traits, super important for you guys that are new. New easy way to do rich text editing and dictation APIs. Thanks a lot, guys.