Frameworks • iOS • 37:34
The iPhone has revolutionized the lives of blind people with its incredible built-in VoiceOver technology — but can they use your app? A few simple steps can expand your user base within this growing community of iPhone users. In addition, adding accessibility to your app makes automating your UI testing much simpler. Discover how your app can be truly universal and simpler to test by adopting the iPhone Accessibility API.
Speaker: Chris Fleizach
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Alright welcome to Accessibility on iPhone OS. We're going to learn how to make an app useable by everyone. My name is Chris Fleizach. I'm on the iPhone Accessibility and VoiceOver team. So when I talk about accessibility, what do I mean? I think about accessibility as using technology to overcome disabilities. So things like closed captioning, things like system zoom, screen readers to help people who can't see the screen use a computer, and there's lots of other kinds of technologies.
So on the iPhone and Apple what do we have for accessibility? Well most of our accessibility options are found in Settings, General, Accessibility. We have a lot of great built-in things. Things like system-wide zoom. We have black on white. In 4.0 we have large text so you can make your fonts bigger in some apps. But what I want to talk about mostly today is VoiceOver. And this will really give you the most bang for your buck.
So VoiceOver is the iPhone's built-in screen reader. It's the first touch-based screen reader. And since we released it in the past year the response has been tremendous. Really we've been blown away by how widely it's been adopted and how quick the community has taken to it. My friend Dean, who is the QA engineer in the front row confided in me earlier that he'd rather get rid of his wife than live for one day without his iPhone.
So, and the reason, half that story is because of Apple. We've done a great job making VoiceOver accessible and work with the all the apps but the other half are app developers making great apps. Not only making great apps that are useful but making them accessible. So I'd like just to read a quote from one our users who said, "I predict that the visually impaired community will agree that the iPhone was the single biggest game-changing piece of technology in the assistive tech industry in modern times." Now that's a pretty bold statement, but with VoiceOver and your apps that is true.
So today we're going to learn how to make your apps even more accessible, make them better for VoiceOver users so we can keep this ball rolling and continue making the greatest accessible product ever made. So before we get into the meat of the presentation, which is learning how to make your app accessible I want to give you a little demo of VoiceOver and some of the things that it can do and also explain what I mean when an app is accessible and when it's not accessible.
Alright so we've got a standard phone here. VoiceOver and Accessibility work on 3GS phones and above. So the first thing we want to do is go into Settings and inside of the General Panel there is this Accessibility thing. We have all our options here. What I want do first is turn on Triple Click Home and this going to be a great thing for you to use if you're testing VoiceOver or you just want to use VoiceOver on a regular basis. I use this myself when I'm driving in the car and I want to change my music but I don't want to look at the screen. So Triple Click I can set that in Toggle VoiceOver.
Now when I use the Home button three times, VoiceOver will turn on. Quickly I'd just like to show you some of the things you'll see in the VoiceOver panel. We've added some great new features in 4.0 including Bluetooth Braille so you can connect a Braille display, we have a way for you to change the language on the fly and we have some great new ways to type. All of these make VoiceOver even better in 4.0. So let's turn on VoiceOver and see what happens.
[ VoiceOver Sound ]
And it's going to speak it back to me. So as I touch around the screen [VoiceOver Sounds] I hear different things. I can also do other gestures to help me move around the screen.
[Background VoiceOver Sounds] Flicking left or flicking right will move me to the previous or next item. Then when I'm ready to press a button I select it once and then I double-tap to press it. So VoiceOver takes all of the normal gestures and changes them in a way that makes sense for someone who can't see the screen. So there's a good reason that you can't just touch an item and press it because if you can't see the screen you're going to be activating things all the time.
Messages stocks.
Something like stocks.
[ VoiceOver Sounds ]
So what we see in stocks is that it's going to give me all the information that I want when I go to it. [Sound effects] I can touch all around the screen.
Incorporated, 15.18.
Get the right stuff that I would expect to hear. The graph down here, which I can probably turn on--
Settings.
WiFi --
Backswitcher stocks.
[Sound effects]
So there's no limits to what you can make accessible and we're going to try to push the boundaries today with another app I have here, which is our app that we're going to be working with called the Bowler app. You can get this in your WWDC sample library.
Bowler no.
Once you get beyond that and see it's sort of a game where you can play things, you can move this ball around and you can throw the ball and score and so on, but if I try to use it with VoiceOver what happens?
[Sound effects]
That means the VoiceOver user can't touch anything. So that part is inaccessible. If I go down to the bottom [VoiceOver Sound] it gave me some gibberish for the name of this button and that's not good either. If I open the button [Sound effects] I found that this was, "Ah Bowling News." If I try to touch [VoiceOver Sounds] I can't even get to the content in that table view so that is an example of an inaccessible app.
Now in the next few minutes we're going to learn how to turn this app into a completely accessible bowling game where everything works as you might expect. So how are we going to make our app accessible? We're going to use the UIAccessibility protocol, it came out in iPhone 3.0, and it allows your app to give the right information to VoiceOver. So how does this work? VoiceOver is a separate app running in the background.
It intercepts all the gestures and touch events that go on. So you might press down on this time and when that happens VoiceOver says what is the element at this point by asking through the UIAccessibility protocol. The app, your app, collects the information that's important, things like what is the TXT of this sends it back to VoiceOver and then VoiceOver can do with it what it needs. It can speak it. It can Braille it and other output devices it might have.
So we're going to find out that accessibility is not only easy to add but you're going to find that most of the work is actually done. So our hard work will be adding labels and that's going to take us 75 percent of the way. So the things we want to focus on today in the Accessibility protocol are the attributes that allows VoiceOver to know stuff about information, containers, which allows us to do some custom work and some new things called actions. So here are the attributes that we have in the UIAccessibility API. There is a few of them.
The most important of them though are things that address the two most common things in an accessible app. One, can VoiceOver get to the element and that is isAccessibilityElement. The other is can VoiceOver speak this element and that's accessibilityLabel. So if you return yes for AccessibilityElement VoiceOver can get to this element. If you give it an accessibilityLabel VoiceOver can speak this instead of some gibberish.
We also have this notion of accessibility Traits. Now traits encapsulate the state, the role, generally the behavior of this item and it uses a bitmask of integers so you can combine things and tell VoiceOver more about the object it is trying to communicate with. So to take a quick example of what I mean by accessibilityTraits so we've got a screen that looks like this. There's a bunch of different elements on this screen.
We've got some static text at the top so that would get a Static text trait. We've got an image in the middle, which would have an Image trait. We've got a button down at the bottom that would have a Button trait and a slider with an Adjustable trait. Pretty straightforward, the naming for those traits is on the reference guide but because these are a bitmask of integers they have a little bit more power.
An object can have more than one trait. For example, that Static text can also be Summary Element. That means when VoiceOver enters that screen that's what it's going to speak first. That button on the bottom can also have the Starts Media Session trait so when VoiceOver presses that button it's going to shut off and not talk while it's trying to play music.
There are some other attributes as well. You won't need them as often because they often come for free if you're using UIKit software. The accessibilityFrame is the onscreen frame of this object. The accessibilityValue is the dynamically changing value of an object. The simplest example is in a TXT field. The content of the TXT field is then an accessibilityValue while the label will describe the TXT field.
Content like [email protected] is the accessibilityValue and label is to field. The accessibilityHint is an interesting little thing. It allows you to provide a little bit more context and help about this object so you can give the VoiceOver user a little bit more help to know what's going to happen.
So how do we add accessibility? The simplest way is through Interface Builder. Once you open up an object and go to the inspector you'll see in the fourth tab there's a little Accessibility section so we have things that you can control like is this an accessibilityElement? You can set the label directly.
You can set the hint directly and you can choose the traits that you want. Now most of the time if you just have a standard UI Kit control like a UI button, UI label all that stuff is just there for you. You don't even have to touch it. If you have a custom element you might need to do that.
So let's take a look at adding Accessibility to an app. So the first thing I want to do, we've got this app running, so I didn't show you exactly how it worked but we can move this ball around. We can select it and then bowl it and then the score changes. So what are the kinds of things we want to do? Well the first thing I'd like to do is add a label to these buttons at the bottom, which we heard were sort of gibberish before.
So we open up Interface Builder, look at these buttons. The first button here we see has got no label, no hint but it is accessible and it does have a button. So let's give it a label like Settings. We've got this other one down here with no label as well. Let's give this a label like Bowling News.
Alright, so that was pretty easy. Let's see what turns out. Alright, so it's very accessible. Can you tell? Alright, so we have problem. So how do we tell that this is now accessible? So what we can do is go to Settings, General, Accessibility, turn this thing on. We're going to get this weird little looking window where it basically mimics the behavior of VoiceOver. So I touch once. It will select something and tell me the label, traits, frame, et cetera about it. If I touch, if I double-tap it will activate that object.
So let's kill our Bowling app and start over again. See if this thing is accessible now. So now if I click on these buttons, say its label, Settings, grade, that's what I added in for this one, label Bowling News. Alright, so we've made those two buttons accessible. What else can we do? So I have the Settings button and some things here that change the ball color. So I can get a yellow ball, a blue ball, all the ball colors you really want. But can I change them through Accessibility? I can't even click on these things.
So what can we do for that? We go back here, open up the right view and now we look at these elements. So what do we notice? They are UI controls. So UI controls don't have any base accessibility on them. We have to add them. So that means checking this box to make it accessible, adding a label, blue ball color and possibly changing the trait. So this one is a button and we want to do the same for all of these. This one is red. This one is yellow.
Now when we check this out we can now select these things. We see that it has a right label. It has a right button. Alright, so what that means is now the VoiceOver user can get to those things and change the ball color. We know how important that is. So that's really how easy it is. We just made something accessible. It didn't require any heartache and that's going to get you pretty far but we can also add accessibility and code in case you have custom views.
So how do we add Accessibility in Code? Well there's two main methods, one would be Setting the value. This would be if your accessibility values don't really change. So say I have a Play button and it's always a Play button. Well I just set that to isAccessibility on YES, set the label Play, we're done, just walk away from it.
But you might have other views that are more dynamic. Say you have like a temperature view where the temperature changes on regular basis. So in this case you would override in your subtask, YES for your accessibilityElement, give it a label like current temperature and you can return the accessibilityValue as whatever the value is for that city. Alright, so that gives us Accessibility Attributes. That gives us a lot of accessibility of how VoiceOver is going to interact with objects on your screen.
What we haven't talked about is what happens when content changes? So there are notifications that allow us to tell VoiceOver when something happens. Like if we look at this example, say I select an album in this iTunes store. We get a completely different screen. In that scenario we want to tell VoiceOver that the screen has changed.
When all of the elements are gone we get a new, basically we get a whole new screen. To do that we send UIAccessibilityScreenChanged. The other kind of content change is when we get just a few things changed, maybe just a label changes a few elements disappear, but it's essentially the same screen.
So for example if I press the Price button it's going to change to Buy Now and all that happens is just the button changed its size and it changed its label. To tell VoiceOver that happened we post a LayoutChangeNotification. Alright, so let's see how we can do some of this in code. We're going to start making our app really accessible. So the first thing, our first problem is that this bowling ball, we can't touch it.
I can click on these buttons down here, even this UILabel, I can't get to the bowling ball. So let's make our bowling ball accessible at the right position here. Where I create my bowling ball object and I'm going to add in a few things. One bowling ball is accessibilityElement. Yes, set the trait to a button for now, give it an accessibiltyLabel and an accessibilityHint. Notice those are localized strings.
VoiceOver speaks over 20 languages. So if we do that, check it out in the simulator, now I can select my bowling ball. I got the hint that says Align the Ball by Tilting Left or Right, When Ready Select the Ball, Then Throw. So that's a pretty good hint to tell the user what's going on. It's not the label obviously, but it's the little bit of extra context to let the user know what's happening.
So another thing we can do with this bowling ball is make it Selected. So when it's in the Selected State it's ready to throw. But if you look at the traits there's nothing that says this is Selected so how would we make the bowling ball say its Selected now? Well I'll go inside of this bowling view, this bowling ball view. We'll go down to where we say Set Ball Selected and we'll change the traits. So if the ball is Selected I'll OrInThisTraitSelected. If it's not selected I'll AndNotTheTrait, which basically removes the trait.
Now if we give this a try we'll see that the traits on the bowling ball change whether it's Selected or not. Selected I might have to click away to get the new selection. Traits Selected you'll see it right here. If we Unselect it the trait is no longer selected. Alright, that's pretty good if we made our bowling ball accessible we're getting there. So another thing we saw was in this Bowling News page.
And our first problem is this RSS button, the tiny thing at the bottom. It says label SM newsfeed BTN. Where do you think that label comes from? Well hopefully the developer didn't set that so VoiceOver will try to take the imaged name if it doesn't have any label. So it will give you something but that's not a good label to have. So let's see if we can change that.
So we'll go into our Bowling News table. Here's our Link button that we create and we can add the appropriate label, a note for the trait, I've set that to a tight link, so instead of a button how come, because when you open it it might open a web page instead of a button. So let's see what that looks like. Alright, we got label more information, the trait is the link and double-click on that, it opens up a web page.
Alright, so we're getting there, so in there you might have noticed there's a big problem in our Bowling News, however, is that we can't get to any of the News and that's kind of important. So how are we going to do that? Well, we have our Bowling News table view cell, which is a subclass of table view and all we have to do is add an accessibilityLabel. So what I've done here is just taken the News title and the News subtitle that are both I bars in the class and return them as a combined string.
So in this way I've combined information that's generally together so that I can click in this one big area and get all of my information together. So this is to serve an important point. In a touch-base interface it's really nice when elements are big and easy to touch when you can't see the screen. So by combining the title and the subtitle I've made this one big area that makes it really easy to get to.
Alright, so I press Done, I don't know if you can see. Our only problem here is that the cursor, that little box is still there. Likewise when I open this up our little box is still at the bottom. So what we need to do is post a ScreenChange notification when this Bowling News appears. So if we go to BowlingViewController again find out where this Bowling News appears and we can send out the right ScreenChange. So after the animation is done I'll post the ScreenChange notification. Likewise when the view goes away I'll also post a ScreenChange.
So now when this button opens we'll notice in the notifications list we'll see a ScreenChange amongst other things but the cursor has also disappeared. When I press the Done button the cursor will also go away. That informs you that the ScreenChange has been posted successfully. So that's Setting Accessibility Attributes. Just wait.
[Applause] Hold your applause, because there's more. Now that's going to get you 90 percent of the way to make your app accessible. How do we do the rest of this? So to get you the next 8 percent or so we're going to talk about Accessibility Containers. Now containers allow you to deal with custom views, things that you draw yourself that might have multiple parts inside of it.
So you would look at a view that looks like this. This month view we might have one UIView that draws all these tiny little boxes there. We need to return separate accessibility information for each of those boxes because they are each separate elements. So we need an element for October 14th.
Likewise we need an element for October 11th. So how we are going to do this? You might think this is really complicated but you'd be wrong. There's two steps. Step one, make the UIAccessibilityElement. This is like a shell to hold all this good accessibility nougats inside of it.
So we make the UIAccessibilityElement. We emit it with its container view and then we start stuffing things inside of it. So we put in a label inside of that. We put in a frame inside of that, the onscreen rectangle. We put in any traits that it might have that might be a selected trait.
And finally we should store this object so that we can reference it. We're going to return this object once we're done making them. Alright, so that's step one. Step two is implement this AccessibilityContainer protocol. So in your custom UIView inside of this month view you're going to basically mirror what NSArray does. So you're going to tell them how many accessible elements you have with a count.
You're going to tell it what is an element at this index, and you're going to tell it what is the index of this object. So three methods that you can implement and they can mirror NSarray, pretty straightforward, and with that you're going to be able to take a custom view and turn it into something that's very accessible.
So let's see how we can do that. So which part of this view is very custom and not accessible? So these frame score things up here, totally inaccessible. I can't select them at all. So how are we going to do this? Inside of my scorecard view I have all this code.
We're just going to go to the bottom and start pasting in things that we want. So the first thing we do is make our accessible framework. So I'm going to have this method accessible elements. It's going to store my accessible objects and return them for me whenever I need them.
So this is just sort of the standard template that you'd want. You're going to check if they're NIL if they're not NIL you'll make the array and return them. At that point we're ready to make our UIAccessibilityElement. So I have three frames that we saw, whatever these two frames are.
So I want to make three of them. Each one I make a UIAccessibilityElement. I've set the container to Self because that's a custom view and I add each one to the array of accessible elements. Alright, so that part's done. I made the accessible elements and now I need to stick some information into them.
So how do I do that? So it depends on where I want to put this but I will put this I think here so inside of this part where I'm drawing this Rect and it's a big method inside of drawRect, I'm calculating the string I want to be so I'll pull out the part that I want for what index of the frame and then I'll set the label to this accessible string that I've calculated, and the accessible string is just what's the score of this frame. So I've set the label. That tells VoiceOver what to speak. It needs one more part however, it needs the onscreen rectangle. So when VoiceOver touches this thing it's going to know where it is.
So I can do that with these three methods and what they do is get me the onscreen rectangle. So I don't want to just pass at any frames or bounds for this view because that won't be the onscreen frame it will be the frame inside of this subframe. So how do I do that? I take my rectangle for this view. I say convert it to the Self window then I ask the window to convert it to a NIL window.
So those two lines take a frame for this view, convert it to the onscreen rectangle, and then I can set it as my accessibility frame and that will give me the onscreen frame. Alright, so I've made the accessible elements, I've stored them, I've put some information in them and now I just need to implement this protocol, the accessibility container protocol.
So I've done that with these three methods, accessibility element count, the index of the accessibility element and the element at the index, which you as you can see just mirror NSarray. Alright, it's going to happen. Now if I touch these things it says Label, Frame 1, 0, it's got the right frame so all these now have the right size. If I try to bowl, 9 pins pretty good. If I check this one again it says frame 1, 9, 9 pins. See if I can get a spare. No. Come on.
Oh a strike. Alright, so now the label says frame 2, 19, You Got a Strike. So that's some good labeling there. That's very informative. So that's Accessibility Containers. We've taken a very custom view with lots of little drawn widgets and made into an accessible object in a pretty short amount of time.
So there's something new in 4.0 called Accessibility Actions. This will get you the final 2 percent to make your app completely accessible. What these do, what this does is basically allows you to make a new kind of custom element that behaves like a slider or an adjustable value. So we have something like in iBooks this Page Controller where you can move it forward or you can move it backwards.
How does a VoiceOver user use that? Well they touch on that object and they perform a different gesture. They perform a gesture like a flick up or flick down to adjust it. So if you want to make an element like this you can just return the trait adjustable for this object and then implement two methods, accessibilityIncrement and accessibilityDecrement and those will do the appropriate things for the object.
So that's a UIAccessibility protocol. Pretty simple, it can make things very accessible as you've seen. So let's go over some good things that you should try to do and you should avoid. Try to be concise in your labels. You don't need to be overly verbose, telling the user all the things they need to do, just something like Add a City is appropriate. You don't need to include the type of information in the label. So don't set your accessibility label to Settings button because then VoiceOver will say, "Settings Button Button." So that information is communicated in the traits.
Make sure to use localized strings for your labels and hints. VoiceOver speaks a lot of languages so if your app is going to be localized make sure that you also use that localization in your accessibility stuff. Remember with custom view table cells this is like the most important part of your app so you don't want to forget about this. Make sure you just add the accessibilityLabel, those things are already accessibility elements. All you've got to do is add that label and your app is going to become very accessible.
Alright, so if we put all these pieces together what kind of game can we make? [Sound effects] So I have the original Bowler with all of those changes that we put in and we're going to see how accessible this game can be.
Bowler score 13, frame 1, 9, 8 pins, then 1 pin.
Alright, that's good.
Okay [Sound effects] you notice there's this little annoying sound. [Sound effects] All right so I can figure if I'm aligned or not. So visually you can see whether this is aligned or not. But if you can't see it you can use sound [Background sound effects] to do that. When we're ready.
[ Sound effects ]
[Sound effects]
[Laughter and applause]
Alright.
Settings.
Blue ball color selected.
[Sound effects] Bowling News. Bowling for babies. Teach your Toddler How to Bowl in this fun and exciting new program.
I can get to this button and set the right thing. [Sound effects] When I close this thing VoiceOver will go back to something.
Frame 1, 9, 8 pins, then 1 pin.
Alright so that's a pretty accessible Bowling game. So if you paid close attention you might have noticed there's some things in there that you probably couldn't do with what we talked about so far. So the 4.0 SDK, we have some new Bonus API for you so that you can really make a great app for a VoiceOver user. One is whether -- is VoiceOver running? So this now available and I was using that in that app to know when to play sounds. VoiceOver is not on, no sounds are played. VoiceOver is on, the sound is played.
Another thing that I use is, is the accessibility element focused? So this tells you where is the VoiceOver cursor on the screen, what element has the VoiceOver user selected? So I used that to determine if I should play that alignment sound on the Bowling ball. If the VoiceOver user wasn't on that bowling ball it wouldn't play that annoying sound.
So in case you haven't noticed we really want you to add accessibility. Not only is it easy but it's also pretty darn fun. That Bowling game which took me probably 20 hours to write took me about 30 minutes to make accessible and that's pretty easy. So you're going to see your user base increase if you do this. You're going to probably make millions more dollars than you're already making, if that's even possible.
You're going to get all kinds of great praise. You're going to be like the hero. You're going to be telling your grandchildren's grandchildren about how you made this thing accessible and people are going to be sending you email all the time about how great you are. And you're going to get all kinds of other intangible benefits for your everlasting soul if you just make your app accessible by setting a few labels.
There's some great documentation. We have the protocol reference for all the new stuff we got up there. We have the accessibility guideline programs, which give you some more helpful hints about how to make your app accessible and the VoiceOver user manual is really cool and it will tell you all the different gestures you can do with VoiceOver in the iPhone.