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-203
$eventId
ID of event: wwdc2012
$eventContentId
ID of session without event part: 203
$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 203] Accessibili...

WWDC12 • Session 203

Accessibility for OS X

Essentials • OS X • 50:52

OS X has a long been a leader in accessibility with its wide variety of features and assistive technologies. Developing an accessible application can make it usable to users with varying abilities. Making your app accessible can open new markets, such as Government and Education, which sometimes require accessible software. Learn from the experts on best practices for developing accessible apps and hear about some of the common issues developers run into while supporting accessibility.

Speaker: Greg Hughes

Unlisted on Apple Developer site

Downloads from Apple

HD Video (291.3 MB)

Transcript

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

My name is Gregory Hughes and I work on the OS X Accessibility Engineering team. I'm really excited to have the opportunity to be able to speak to you today about accessibility on OS X. Today we're going to talk about how to make your applications, your custom UI, your really robust interfaces accessible for all users.

There are three main areas of today's talk. We're going to start out and talk about technologies. This is going to cover some of the assistive technologies that Apple includes in all of our products, and we're also going to talk a little bit about why you might want to include accessibility in your software. We're then going to talk about the API. This is the API that you're going to use to make your software fully accessible. It's a really rich and robust API. It's incredibly powerful, yet also easy to use.

Finally, and perhaps most importantly, we're going to look at some case studies of custom UI. When doing research for this talk, we looked at a lot of different applications, talked to a lot of different developers, and we found that one of the places that developers often get hung up is making their custom UI accessible. And so we wanted to go through a few case studies of how you'd approach completely custom UI and custom drawing routines and making them fully accessible to all users.

So, first I want to start talking about technology. And to start off, I want to reflect on something that Tim Cook said in yesterday's keynote. Tim said, "The products that we make, combined with the software you create, can fundamentally change the world." Those are really powerful words, right? Fundamentally change the world. Here at Apple, we truly believe that. We truly believe that with your help, we can change the world.

Greg Hughes And part of that is by making software and hardware fully accessible for all users. And this is so important to us. We work so hard and spend so much engineering time and resources in creating really magical products that we want everyone to be able to pick up the same product, experience the same sense of magic and intrigue and exploration when they use any of our products, regardless of their abilities or disabilities. Greg Hughes And so accessibility is incredibly important to us.

And so accessibility is incredibly important to us. We don't just talk about accessibility. We deliver accessibility. We have a ton of accessibility features throughout the range of our products to help users with a varying degree of abilities. On OS X and Mountain Lion, we've continued to push the bar and continued to implement various accessibility features that are going to really help our users.

And so accessibility allows you to turn on or turn off various accessibility features no matter where you are. So if you're at the login window, in Xcode, or in a full-screen mail application, you can enable or disable accessibility features really, really simply and easily. So this is going to help our users a lot in providing them the functionality to get to the features they need to very quickly.

Now, we also have a lot of in-depth features, of course, and so to help users get to those more easily, we've redesigned the accessibility preference pane. This new redesign helps users get to features much more quickly and easily. We've grouped things better and provided more intuitive UI to customize the various assistive technologies.

We've also continued to work really hard with closed caption content providers in creating as much content as we can on the iTunes store. And of course, closed caption content is available for playback on the Mac, on iTunes, on all iOS devices and iPods. We've continued to push the bar of accessibility on iOS. As you heard yesterday, we've introduced some great new features like guided access. We've done a lot of improvements to VoiceOver as well in iOS 6.

One of those products on iOS and OS X is VoiceOver. It's a screen reading software for users who are blind. What a screen reader does is takes the graphical user interface and converts it into a spoken interface for users who can't see the screen. And primarily today I want to talk about how we're going to make our software accessible for this product.

I really want to focus on it because it's one of the big challenges of software design. We spend so long working on our graphical user interface, our point and click interface, dealing with mouse events, that oftentimes it's easy to forget about users who can't see the screen or users who can't use the mouse. It's also challenging because sometimes some of these graphical user interfaces are so mouse oriented that it's difficult to think about how someone might use it without a mouse. And so we'll talk a bit more about that in a little while.

VoiceOver now has been shipping on the Mac for about six years. : VoiceOver is also available on a wide range of our other products. VoiceOver is on OS X, on Apple TV, on iOS, on the iPod Nano, the iPod Shuffle, and the iPod Touch. So this is really important. The voiceover ships with these products because someone who's blind now can walk up to any Mac and turn on voiceover and use it.

So this might not seem important at first glance, but what this means is that someone with a disability now can walk into a public library or walk into a school lab and use the same computer as the rest of us. Someone with a vision impairment can walk into an Apple store, pick up an iPad and feel the same sense of magic as everyone else that comes into an Apple store. And this is what's so important to us, this inclusive technology that anyone can use. As I said, on the Mac, VoiceOver has been shipping for six years and it's currently installed on millions of Macs because it ships for free with every Mac.

So our install base is enormous. And it's also important to note here that our install base is larger than all of the other competing screen readers combined. And so by far, we have the largest install base. And this is really important because you really get the most bang for your buck making your software accessible for VoiceOver. compared to other products.

Now, VoiceOver also has a lot of unparalleled features in the world of screen reading technology. For example, we have amazing plug and play Braille support. We support a huge list of Braille displays, both Bluetooth and USB. And they don't require drivers or sighted assistants to configure them. You can just plug them in and they work right away.

Greg Hughes And so this is another thing that's really important to us, to be able to allow users to be independent, use the technology on their own without requiring assistance from other users. And we work really hard to continue to create features like that and also create a really collaborative environment, as you'll see in a little while.

So those are some of the products. A small sample of all of the assistive technology that we work hard here at Apple. But you might be wondering yourself, well, why is accessibility important? Why do you want to implement accessibility in your projects? Well, as I talked about, the first thing is access to everyone. We work so hard on our software and our hardware that we want to go that little extra mile to make it fully accessible.

You work really hard creating these amazing applications that provide a lot of functionality to users. In every case, it's always worthwhile to do that little extra 5% of effort to make that software accessible to everyone, regardless of their abilities. Accessibility is also important because it can help expand your user base. And it can help expand your user base by a huge amount. In the U.S., there are 10 million Americans with vision impairments, 31 million Americans with hearing impairments, and 12 million Americans with learning disabilities.

When you add all of this up, one in five people in the U.S. has a disability. That's 50 million Americans. . Think about that for a second. 50 million Americans have a disability. This is a huge audience for you. So because of all the technologies that we've included in every single Mac that we sell, every single iOS that we sell, we've opened up an enormous market for you to take advantage of and for you to implement and create wonderful software in.

The best case of this that we've seen is the education market. For students with disabilities, this market has exploded. And it's such a new market. It's such a market that's available for you to create new applications and really take advantage of the openness of the market. and your ability to innovate.

So, accessibility is also important because some markets require accessibility. For example, in the US, a lot of government and education markets require software that they purchase to be fully accessible. This is obviously a key thing. If the market requires this, you're going to need to implement it in order to compete in that market. And also, since the market requires this, there aren't a lot of other competitors. So it's a pretty easy market to compete in if you implement your accessibility.

And finally, it's a great way to gain a competitive edge. The accessibility community is a really vibrant and vocal community, and we've seen a lot of applications go viral just because the developer spent a little bit of extra time and made their application accessible. So, it's a great way to really increase your user base, compete in new markets, and provide access to everyone.

But how are you going to do this? How are you going to implement this accessibility? Hopefully now I've convinced you that it's the right thing to do, that you're going to want to do this for your projects. I'm sure you're wondering now how to do it. Before we really dive into the API, I thought first we'd take a look at what the API actually does, how the API works with VoiceOver. And to do that, I wanted to start with a demo. So here I'm in Calculator. I'm going to start VoiceOver by pressing Command F5 and we'll hear a short welcome message.

Welcome to VoiceOver. VoiceOver speaks descriptions of items on the screen and can be used to control the computer using only your keyboard. If you already know how to use VoiceOver, press the V key now. If you want to learn how to use VoiceOver, press the space bar now.

So this is the welcome message for VoiceOver. It's a great opportunity for users if they accidentally turn on VoiceOver to cancel out of it. This is also a really good opportunity to learn how to use VoiceOver. Now, VoiceOver, as I said, is for users who are blind. And this class of users isn't going to be using the mouse to navigate the interface. So in order to accommodate, VoiceOver has a lot of custom keystrokes.

So if you've never used VoiceOver before, I'd strongly, strongly recommend that you go through our tutorial to learn how to use these keystrokes. It'll walk you through some examples and give you an opportunity to practice with VoiceOver before you're let loose in the OS with VoiceOver. I happen to already know how to use VoiceOver. So as instructed, I'm just going to hit the V key.

[Transcript missing]

So I'm now going to use some voiceover commands and navigate around. You'll hear various buttons and we'll do some simple math in the calculator. . Three button. Press three button. Six button. Add button. Press add button. Six button. Press, six button. Add button. Equals default button. Press equals default button. Nine.

So, by using Voice over here, I was able to navigate around the app, hear various buttons, and also press on those buttons and then finally get to the results. So, the question now is how is VoiceOver doing this? How is VoiceOver getting all of this information from the calculator application? VoiceOver off.

Well, Calculator is its own application. It's running in its own process space. VoiceOver is also its own application. It's running in a completely different process space. VoiceOver is not running in the same process space as all of the other applications. So there's obviously some kind of communication going on here. And between these two, there's an IPC layer, an interprocess communication layer, that happens to use Mach messaging. But you really don't need to worry about that layer because we wrap it up really, really nicely with the NS Accessibility Protocol.

So we deal with all the packaging, all the communication between the application and VoiceOver or the application and any assistive technology. And you just need to adhere to the NS Accessibility Protocol and we'll do all the other heavy lifting for you. So, what does that protocol look like? What does it do? The protocol provides a lot of things. One thing that it provides are things like the description.

In Calculator, the description and the title of those buttons were things like 6 or plus. And with all standard Cocoa controls, you're going to be able to provide that information right in Interface Builder. In Interface Builder here, we're looking at the inspector, and you can see you can provide the accessibility description, the help tag, the title element, and the linked element. So for all your standard Cocoa controls, it's going to be really easy to provide accessibility. And we'll take a little bit deeper look at that in a bit.

But the point here I want to make is that you should always use standard Cocoa controls whenever possible. Now, I said in the beginning that we're going to look at some custom UI, and we wholeheartedly know that it's not always possible. But the first thing you always want to think about when you have a piece of UI is if you can use a Cocoa control, you should. Because you're going to be able to take advantage of all the accessibility work that we've done, all of the event handling work that we've done, and really also take advantage of any changes that come in the future.

So what if you're not using a standard Cocoa control? What if you have a custom control? Well, we have a nice little recipe for custom controls. First thing you're going to want to do is subclass appropriately. So if you have something that looks kind of like an NS Button, behaves kind of like an NS Button, but you have some little slightly different functionality, it's probably going to be best to inherit right from NS Button and NS Button cell.

Part of the reason for this is that we work really, really hard to make your job as easy as possible. We want to do as much work as we can so that you can make your applications accessible. Thank you. In doing that, we will provide a lot of accessibility functionality on NS Button to begin with. If you have something that behaves like a button and you inherit from NS Button, you will get a lot of our accessibility work for free.

So after you've subclassed appropriately, you're going to want to figure out what accessibility attributes you need to provide for your specific UI. The way to do this is to look up the Apple documentation accessibility attributes and roles reference. And here we're looking at the attributes that we need to provide for a button.

This will tell us what attributes are required and what attributes are optional for a button. For a button, there's about 10 attributes that are required and one action that you need to implement. As we'll see later, you don't need to implement all of these. It's actually much, much more reasonable.

Another way to get to that information is to use Accessibility Inspector. Accessibility Inspector is a tool that allows you to hover the mouse over any piece of UI and it will show you all the accessibility information. This is a great tool for figuring out which of the optional attributes you might want to provide. So the documentation will tell you what's required. The optional attributes you can figure out by looking at any other piece of UI that you want to mimic and look at what accessibility attributes it supports.

Accessibility Inspector is even easier than ever to get to. Right now you can just click on the Xcode menu, then click on Open Developer Tool and Accessibility Inspector is right in that menu. So there are some great WWDC talks in the past that go into more depth on Accessibility Inspector and how to use it, so I'd strongly recommend looking at those if you're more curious about Accessibility Inspector.

So we've subclassed appropriately and figured out what attributes we need to support. How do we actually support them now? Well, to do that, we're going to use the NS Accessibility Protocol. This is the API that provides the accessibility information to any assistive technology. There's really six key main parts. First is ignored.

As we'll see in a little bit, this is where a lot of developers get hung up. You want to make sure that your custom UI is not ignored by accessibility. Next, attributes. Attributes are things like title, description. And for an attribute, you're going to need to provide which attributes you support, a getter for those attributes, and a setter for those attributes.

We then have parameterized attributes. And these are attributes that take a parameter. For example, string for range or line for index. Just like attributes, you're going to need to provide which parameterized attributes you support, and you're going to need to provide a getter for those parameterized attributes. Actions are similar. Actions are things like press, increment, or decrement. For an action, you're going to need to provide which actions are supported and the ability for VoiceOver to perform those actions.

: Hit testing and focus testing is really important, but for the most part, we're going to do all of this work for you. It's something to be aware of. In some advanced cases, you're going to need to implement these. And again, there have been some great past WWDC talks on advanced accessibility, which we'll talk more about these. But hit testing and focus testing help VoiceOver figure out what's on the screen. If your hit testing doesn't work, then we can't figure out what's under the mouse, and things like accessibility inspector also won't work.

Finally, notifications, which are probably the most advanced part of this API. You rarely need them, but notifications are for doing things like informing voiceover when the focus changes or the value of an item changes. So, those are the six key parts. How do we actually implement them? Well, first accessibility is ignored. As I said and I will say multiple times again, this is really important. By default, NSVue is ignored by accessibility. So if you inherit from NSVue, your view is going to be ignored by accessibility and completely skipped over by voiceover.

We do this because in a lot of applications there are tons of NSVues. We've seen 10 or even 100 NSVues deep just to get the layout that a developer wants. So we can't let a voiceover user land on every single one of those hundreds of empty NSVues or NSVues that are just there for formatting. So we ignore NSVue by default.

Then there are the attributes. As I said, you're going to need to provide which attributes are supported. You're going to do this with accessibility attribute names. And you're going to need to provide a way for us to get at an attribute. You're going to do that with accessibility attribute value. This takes in an attribute and returns an object that represents the value of that attribute. Now, attributes are also settable.

So you're going to implement the accessibility attribute is set-able method and accessibility set value for attribute method to allow VoiceOver to set a specific attribute for your value, for your object. Now, parameterized attributes are pretty much the same way. You're going to report which attributes you support by responding to parameterized attribute name, accessibility parameterized attribute names.

And you're also going to provide a way for us to get the value for an attribute given a specific parameter with accessibility attribute value for parameter. So this is where something like range for line will take in a line number and return NS range for that, as we'll see in a minute.

Now, there are also actions. Just like attributes, you're going to need to provide which actions are supported with accessibility action names. This is going to return an array of action names. For example, things like AX Press or AX Increment. Then you're going to need to provide a way for us to get a description, a human readable description for an action. It's accessibility action description. And finally, you're going to need to provide a way for us to perform an action. Accessibility perform action.

Finally, hit testing and focus testing. As I said, one of the more advanced parts of the protocol. Given a point, you would return an object that represents the accessibility object at that point. Assuming you're inheriting from NSVU, we're going to do most of this work for you. Same thing with accessibility focused UI element. This is the element that currently has keyboard focus. So it's really, really important that both of these behave correctly in order for voiceover to work correctly.

Lastly, we have the notifications. And posting notifications is something you will do with the value changes or you need to do something special with keyboard focus. But again, for the most part, we're going to deal entirely with notifications for you. It's just something to be aware of. It's one of those pretty advanced parts of the protocol, which you can learn more about in the past advanced accessibility talks.

So we're going through our recipe again. First thing we've done is subclassed appropriately. We've figured out what attributes we need. We've figured out what NS accessibility protocols we need to implement. One key part of this is to always call super. As I said, we work really hard to make your lives as easy as possible. We want to do the hit testing for you when we can. We want to do the focus testing. We want to report the bounds and the position on screen of every object that we can.

So you need to allow us to do that, and always call super for any attributes that you don't handle. And we'll see lots of examples of this. But accessibility is ignored, and forgetting to call super are two of the biggest problems I've seen developers run into. And they're really, really simple things to fix once you know about them. Finally, we're going to want to test our results. We're going to want to look at our application, look at it with voiceover, and see how well it behaves with all of the new accessibility information.

So, let's look at a few case studies now. Let's look at some custom UI that does its own drawing, its own event handling, and how we might make them accessible. There are four pieces of UI that I wanted to look at today. First, a pretty simple button. It does its own custom drawing, it's going to have its own highlight state, and do some other special things that we couldn't get with a standard NS button. Then, a custom text area, a static text field. This might be used in something like a greeting card application or a presentation application where you can't use the standard NS text field or NS text view and you want to do your own text layout.

Then we're going to look at a multi-line, multi-column text field. This is the same case as before. We want to do our own text layout, use our own text rendering engine. : We are still trying to make it accessible for users with visual impairments. Finally, we're going to look at a custom stepper.

Now, in this case, from our HI team, they wanted a stepper with a specific look, a specific animation, and our engineering team decided the best way to do that is with OpenGL. So, in this case, we're going to actually look at how you would make something that's drawn entirely in OpenGL fully accessible.

We're going to look at this today with our sample app called Accessibility UI Examples. This app is available for download and you can look at all the source code, so don't worry about feverishly writing anything down. So let's take a quick look at that now. So here we have our application.

And the first object here that we're going to look at is just a standard Cocoa button. It says Apple on it. And when I press it, the press count increments. Next is a standard NS button that has an up image and a down image. Again, this is just a standard control.

Next we have our custom button. And this we created because we wanted more functionality than the standard button could provide us. In this case we wanted to have a highlight state so that when I hover my mouse over the button it changes highlight. And it also has the up image and the down image. Then the core text arc.

The multi-line, multi-column text field. And finally, our custom stepper with custom animation. So the first thing we're going to want to do is take a look at these with voiceover. So let's turn on VoiceOver now and navigate through and see what we hear. VoiceOver on accessibility UI examples copy. Press count two. Apple button. Press Apple button.

So we see here I was able to navigate to the standard control and use it just fine. This is a really important point. For this standard button, I literally needed to do no work to make it accessible. This is where we're continuing to work hard to make your lives easy.

When you make a standard button like this with a standard label, it's fully accessible right out of the box. And as I navigated there, I landed on that label that said press count. That's a standard NS text field. So again, fully accessible right out of the box. You need to do zero work for those. Greg Hughes Let's look at the next example where I have a button that's just an image. And as button with image, press count for button.

So here, VoiceOver just says button, because that's all of the information that we have. We don't have any other information other than this is a button. So since this is a standard Cocoa control, this one's really, really simple to fix, and we can do it right now. VoiceOver off.

If we launch the project in Xcode, right here I have the nib loaded. If I click on the button and look at the identity inspector, Under here you see accessibility identity and I can enter a description right in here. So I'm going to type in Apple, save and run my project. And now let's look at this again with VoiceOver. VoiceOver on. Accessibility. Press count. Zero. Button. : Something went wrong.

Let's try that again. VoiceOver on. Press count zero. Apple button. There we go. So we now land on the button. It says Apple button. Really, really simple. Just a quick change in the nib. So let's look at the next case, our custom button. Custom button. Press count zero. Apple button. Close. Voice over off.

Sorry, that wasn't supposed to work yet. VoiceOver on accessibility UI exam. Let's look at the custom button now before I run the example that has all the accessibility work done. Press count zero. An example of a custom. So here, VoiceOver skipped right over the button. VoiceOver didn't even land on it. VoiceOver knows nothing about it. And this is because there's no accessibility information for VoiceOver to get to.

This is also because right now it's reporting that it is ignored by accessibility. Let's look at the custom arc. Core text arc. An example of table. An example of table. So again, I can navigate around it, but I can't actually land on the text. Our multi-column sample. Core text columns. An example of a Zen app table.

I can navigate around it, but I can't land on it. I'm sure you can guess what will happen with the stepper, I'll be able to navigate around it but I can't land on it. This is because none of the accessibility information is there for VoiceOver to get to.

This is also the point at which a lot of developers feel frustrated. They feel that VoiceOver can't get to any of their UI and it's hopeless and they might as well not do anything. You'll see in a little bit that it's actually really simple. Just by saying that accessibility is not ignored for your view, you're going to let VoiceOver land on it. And then you're just going to need to implement a few methods to provide a great accessibility user experience.

VoiceOver off. So let's start by looking at how we're going to make a button fully accessible. Well, we're going to follow our recipe that we outlined earlier. We're first going to subclass appropriately, figure out which attributes we need to implement, implement those attributes, and finally test. Now, for the purposes of demonstration, if I had subclassed from NSButton and NSButtonCell, I could have done all of this work right in Interface Builder. So it wouldn't really have made much of a demo.

We also learned that a lot of developers are dealing with some legacy code, some code that perhaps was written quickly to meet a deadline. So you don't always subclass appropriately, although you should. In the real world, it doesn't always happen. So for demonstration purposes, we're going to skip that step and just look at what would happen if we had an NS button that was -- we created our own button that was a direct subclass of NS view.

So first we're going to refer to our documentation and figure out all of the attributes that we need to provide and the one action, the AXPress action. Now, as long as you remember to call super, NSView is going to provide much of this for you. We're going to give you as much accessibility information as we can, and you're only going to need to provide the role, the description, and the AXPress action.

So really simple when we start stepping through it and looking at what accessibility we actually need to implement. So how do we implement these three things now at the NS Accessibility Protocol? Well, first, as always, remember to return that your element is not ignored by accessibility. Really, really important to do and will save you hours of frustrating debugging time.

: We're then going to report which attributes we support. There's a little bit of code here, but it's pretty simple and straightforward. We always want to call super. In this method, we're going to figure out what attribute super supports. We're going to get that array back. Build up an array of attributes that we want to support, in this case, the role in the description. : We're going to add the attributes we want to support to the attributes that super supports and we want to make sure we don't create any duplicates in that array.

So really simple and straightforward, we get the array from super, we add our attributes to it and make sure not to create any duplicates. Then once we've reported which attributes we support, we need to provide a way to get at those attributes. We're going to do this with accessibility attribute value. This method will take in an attribute and return an object with that attribute's value.

So first, when we're asked for the role in this case, we're going to return that this is a button. When asked for the description, we're going to return a human readable string that is the description of this button, in this case, Apple. It's important to note here that this is also localized because we want this to work in multiple countries as well. Finally, and as always, don't forget to call super. This is really important because we're going to respond to things like the position on the screen or the bounds of this element. So if you forget to do this, a lot of the accessibility won't work.

We're then going to need to support the action. And supporting actions is just like supporting attributes. We're going to return an array of actions that we support. Again, just like attributes and just like any accessibility method, we always want to call super. So in this case, we're going to figure out which actions our super class supports and then add the AX press action to that array, assuming it doesn't already include it.

Greg Hughes So one tip here that you might want to keep in mind is whenever you write one of these accessibility methods, your first line of code should probably be a line of code that calls your super class, because that line almost certainly needs to be in your method somewhere.

Just like responding to attributes, we're going to need to respond to actions. We're going to need to provide a way to perform an action. So, When we're asked to perform the press action, we're going to perform our own internal press. Any other actions that we're asked to do, we're going to let Super handle them.

: So really simple and straightforward. There were just a few methods, a few lines of code, and as we'll see later, now our button -- actually, in this case, as we already saw, once we implement this accessibility, our button is fully accessible. But what about our text field? I'll show you the text field is a little bit more complicated.

Again, if we look up the attributes that are required for a text field, we get this list of about 12 or 15 attributes. NSVUE is going to provide most of these for us. So NSVUE does a lot of the heavy lifting. We're now down to this list of seven attributes. And most of these now are things that we're going to need to do. But our static text field doesn't support selection. It doesn't support keyboard navigation. So since it's just a standard static text field, we don't need to support this selection information.

So now we're just down to four simple attributes. We just need to implement the role, the value, the number of characters, and the visible character range. So again, at first it seemed like an overwhelming amount of information, but when we break it down and walk through it with our recipe, it's really not that much information that we need to provide.

So how are we going to do that? Well, we're going to use the same API, the same process as before. First, as always, make sure to return no that your object is not ignored by accessibility. Then we're going to report which attributes we support. This is the same exact format as we saw in the button case. In this case, we're just going to add the role, value, number of characters, and visible character range to the list of attributes that we support.

Now, how about actually implementing them? Well, we only have one more attribute, but it's still pretty simple. First, when we're asked for the role, we're going to return this as a static text area. When asked for the value, we're going to return the value that we're displaying on screen. This is just the string that we're showing in the curved text.

When asked for the number of characters, surprisingly, we return the number of characters. If you note, this method always returns an ID. So you want to make sure that you're always encapsulating your return value in an object. In this case, we're encapsulating the number of characters in an NSNumber.

Finally, the visible character range. In this case, we know that our entire string is visible on screen, so we're just going to return a range from zero to the length of the string. And we're going to stuff that in an NSValue so that we can return it as an object.

Finally, as always, don't forget to call Super so that we can do some work for you. You don't want to be implementing all of the extra accessibility methods if you don't have to. So there's only one extra attribute -- sorry, two extra attributes on top of an NS button that we needed to implement.

And as you'll see, that now made our completely inaccessible text field become a completely accessible text field that a voiceover user can navigate and get to the text of. And it doesn't take that much work. And assuming that you're subclassing appropriately in your own project, you're probably only going to need to do this in a few places. And now all of a sudden all of your custom text fields are going to be accessible.

So next, as we're increasing in difficulty, we're going to look at a multi-line, multi-column text field. This is a great example of a text field that you might see in an e-book reader or a magazine reader or an application that's displaying a lot of text on screen at one point in time. Now, we could implement this exactly the same way we did with a single line text field. We could implement the role, the value, the number of characters, and the visible character range.

And that would be okay. That accessibility would work. The problem is that now a voiceover user is going to land on that, and they're going to hear the entire string all at once. So just like there's good UI and a better UI, there's good accessibility and there's better accessibility.

In this case, we want to provide better accessibility. We want to provide accessibility where the voiceover can navigate line by line or character by character, paragraph by paragraph, and really interact with the text, be able to reread sentences or pronounce specific words phonetically so that a user knows how to spell them. Greg Hughes So just like there's good UI and a better UI, there's good accessibility, and there's better accessibility.

In this case, we want to provide better accessibility. We want to provide accessibility where the voiceover can navigate line by line or character by character, paragraph by paragraph, and really interact with the text, be able to reread sentences or pronounce specific words phonetically so that a user knows how to spell them. so that a user knows how to spell some more complicated words.

To do this, we're going to implement a few parameterized attributes. The attributes that we're going to implement are string for range, attributed string for range, line for index, range for line, and bounds for range. And these six attributes are kind of the secret sauce that are going to allow VoiceOver to navigate line by line in a text field with multiple lines.

So, we just already saw how you would implement the accessibility for a single line text field. We're going to do all of that same accessibility for the multi-line text field. And let's just jump right into what we now need to do for the parameterized attributes. Well, just like regular attributes, we're going to need to return our array of all the parameterized attributes that we support. First, we're going to call super, figure out what parameterized attributes super supports, build up an array of all the parameterized attributes that we want to support, and then merge the two arrays, making sure that we don't create any duplicates.

So then what about responding to these attributes? We're asked for a parameterized attribute and we're given a parameter. The first one, string for range, we're passed an NS value that contains an NS range and we're going to call our own internal method that returns a string for that range.

Now, one thing that's important to note for parameterized value for -- sorry, accessibility attribute value for parameter is that We guarantee the parameter is going to be an object. We don't guarantee what type it's going to be. You always want to make sure to type check the input parameter and make sure it's the type you expect. Otherwise you can run into big problems if you start passing string methods into something that's an NS value. In this case we're expecting an NS value. We first made sure it was an NS value and then we got our range out of it.

So, pretty much the same code for attributed string for range. When we're asked for the attributed string for range, we type check our input value, we extract the range from the input value, and then we call our own internal method that just gets the attributed string for that range.

: So, the range for line -- sorry, line for index, given an index, again, which comes in as an NS value. We're going to extract the index out and then call our own internal method that's going to return a number for that line. And just as we saw before, we're going to bottle this up in an NSNumber so that it can be returned through that IPC layer.

Range for line works pretty much the same way. We're going to extract the line number from the input parameter. We're going to call our own internal method to figure out the range for that line. And finally, we're going to bottle up the return value in an NS value so that we can return an object.

: Balance for range is a really important one as well. Balance for range is what enables VoiceOver to draw that VoiceOver cursor on screen correctly. This is incredibly important for collaboration so that users can work together and a sighted user can see where a VoiceOver user is currently located on screen. So bounds for range takes an NS value, we extract the NS value, we call our own internal method to get the bounds, and then we bottle that back up in an NS value and return it.

And as always with all of our methods, we always make sure to call super. Really, really important again because we also will respond to some parameterized attributes for you. That's all there is to it. There's a little bit of code, a little bit more code than the previous example. But one thing to keep in mind is that the amount of code here that we needed to do for accessibility pales in comparison to the amount of code I needed to write to get this to draw and screen this way.

Whenever you are looking at drawing something custom, doing your own drawing routines, doing your own text layout, you always have to do more work to do that drawing initially. When you do that extra work, you will always have to do a little bit more accessibility work as well.

This you should take into account when you are deciding if you should use custom controls or use existing app kit controls. Finally, we're going to look at a custom stepper. In this case, it's a volume stepper. It increments and decrements the volume. And in accessibility, we refer to a stepper as an incrementer. So we're going to look up the accessibility information that's needed for an incrementer.

So, just like our previous examples, we have quite a bit of information that we need to provide. But as always, as long as we call super, NSVU is going to provide as much of that information as it can. So we're down to just a handful of attributes. We need to provide the role.

We need to provide whether it's enabled, the description, the children, the increment button, and the decrement button. So the first time here, you see children. Children is an interesting one, right? We haven't seen that yet. Just like there's a structure of your views, you have a super view that has sub views, accessibility has a structure. Every object can have accessibility children. In this case, an incrementer has to have accessibility children. It has to have a child that's an increment button and a decrement button.

: This is a problem for us because in this case we don't have children. We just have one view that's drawing both of these buttons. So, what are we to do? Well, we're going to create what we call faux UI elements. This is an important concept in the accessibility protocol that every object that's represented in the accessibility information, every piece of UI that's represented to accessibility has to have an object backing it. It has to be an object to respond to the methods and report all of the accessibility information.

In this case, we've distributed a really great class called the Faux UI Element class. And this class is just meant to bottle up that information. It's just a really lightweight object that responds to accessibility requests. Here, this is going to be my own internal method for building up my fake children. I'm going to create a Faux UI Element for my up button and a Faux UI Element for my down button and return that array.

There is a little bit more involved in reporting attributes on FOA UI elements, but you'll be able to take a look at that in the example. So now how do we provide the rest of the accessibility for this bot? Well, as always, we need to start with accessibility as ignored. Make sure that we return that we're not ignored. For the accessibility attributes, this is the same method we used before. We're going to add the attributes that we want to support into the array of attributes that Super supports, making sure not to create any duplicates.

And now, how do we report these attributes? Well, first, when asked for the role, we're going to return that this is an incrementer. When asked for the children, we're going to turn the array of full UI elements that we built up. When asked for the increment button, we're going to return the first child because we know that we put the up button in position zero. And for the decrement button, we know that we put the down button in position one.

For description, we're going to return the human readable localized string for this incrementer. In this case, it's our volume incrementer. And finally, as always, we're going to make sure to call Super. Super is going to handle a lot of the other things, and by calling it, we take advantage of all of that work. We also saw that there were two actions we needed to report. So we're going to need to add the increment and the decrement action into the array of actions that our superclass supports.

And finally, we're going to need to be able to perform those actions. So when asked to perform the increment action, we call our own internal method to perform an increment. And when asked to perform the decrement action, we perform our own internal method to perform the decrement. That's all there is to it.

Again, there was a little bit more code, but this is a pretty complex example. We were creating our own fake elements just to support accessibility here. This example can be extrapolated. You can make anything you can draw on the screen fully accessible. A game that was done entirely in OpenGL could use the same technique, the same foe UI elements and make the entire user interface accessible for someone who can't see.

So let's take a look at our app now that it's finished with all of that accessibility information in it. So here's our app. And first we're going to start with the custom button. I'm going to turn on voiceover and navigate to that button. Voiceover on. Press count zero. Apple button. Press Apple button. So you see now it's fully accessible.

Next, the Cortex Arc. Cortex Arc. Hello, world. Fully accessible again. The voiceover cursor draws correctly around the text. We have the Cortex multi-column view. Cortex columns. Text, Apple designs Macs. Interact with text, Apple designs Macs. The best personal computers in the world, along with OS X, iLife, iWork, and professional software. Apple leads the digital music revolution.

So you see, voiceover now can go through and read each sentence. But I can also navigate line by line or word by word. Online store. It's iPods. And app music revolution. Apple lead digital. The leads. Apple. Or even character by character. P-P-P-L-E. So really, really powerful now with that little bit of extra effort. We've created great user experience for a user using something like an electronic textbook or a text messaging application that has a lot of text that a voiceover user needs to get through.

Finally, our custom stepper, or as we call it in the accessibility world, an incrementer. Custom stepper. Volume stepper. Interact with stepper. Stop interacting with stepper. Interact. Volume incrementing. Volume incrementing. Volume incrementing. Volume incrementing. Volume decrementing. So now I can interact with the stepper. I can control it. I can increment the volume and decrement the volume. So really, really powerful now, a view that was entirely in OpenGL. One view drew multiple controls. And I was able to make it fully accessible with VoiceOver with just a handful of code.

So as I said, this demo code is available for you on the WWDC website. And it's a great example of some UI. There are also some bonus examples in the code. If you download it, you'll be able to take a look at. And I'm sure right now you're thinking about a lot of your UI, how are you going to make it accessible, and what you need to do. And Apple has a lot of great resources for you.

One great starting point is the accessibility web page on Apple.com. It's Apple.com/accessibility. This web page is a great starting point because it provides links to the developer information, it provides links to mailing lists, and it shows all of the accessible products that Apple works on. I also have some great contact information here, including our application technology evangelist, the developer mailing list, and the accessibility mailing list, which are all great resources to ask your accessibility related questions to.

So in summary, we talked about a lot today. We talked about the various technologies that Apple works on, how important accessibility is to us, how important we feel accessibility should be to you. We looked at some of the APIs and how to implement accessibility. And we did a few case studies, which do two things. They provide specific examples on how to make some specific pieces of UI accessible.

But they also highlight that pretty much anything you can dream up, our API can support. Any pixel you can render on the screen, we can make accessible with our API. And so thinking about custom controls, I don't want you to stop at the four examples I gave you, but use those as a starting point for thinking about how you can make your API accessible. you might make other custom controls accessible.

And I want to come back to the words that Tim said yesterday, that we have the opportunity to dramatically and fundamentally change the world. I truly believe that and I really hope you can help us change the world by helping to make your software accessible. Thank you very much for your time and I hope you have a great rest of the week at WWDC.