Accessibility in iOS: Hands on Code

Accessibility in iOS: Hands on Code

Pramod Kumar
SwiftCommmunity
Published in
7 min readMay 3, 2020

--

So, we know enough about accessibility as per our last discussion.
We will be creating a contact list application for making hands on code. We will use MVVM architecture and and API based data for populating a UITableView using Swift in iOS.
Before we can go ahead for implementation in code, need to discuss about accessibility attributes.

Accessibility Attributes

Accessibility attributes help assistive application to know how an accessibility element behaves or should be treated by setting these.
These attributes provide information from application to VoiceOver, can be announce to user. If these attributes don’t have proper information then VoiceOver will not announce as expected.
There are some accessibility attributes as:

  1. isAccessibilityElement: a bool value decides wether element should be exposed as an accessibility element or not. Default is false.
  2. AccessibilityLabel: a string to summarily identify the control or view, but shouldn’t include type. For example: label for back button should be Back not Back Button.
  3. AccessibilityTraits: describes aspect of element’s usage, state or behaviour. Some traits may be combine (by an OR operation) as per requirement. For example: button may have .button or .button, .selected traits.
  4. AccessibilityHints: describes the result of performing an action on element. For example: a favourite button may have makes favourite or removes favourite not Double tap to make favourite.
  5. AccessibilityValue: describes the current value of element. For example: a textField will have same value as text property.

These are the essential properties for implementing the accessibility in application.

📣 Most of the UIKit elements already set these attributes for you, just need to supply details for improve user experience.

We will be using standard UIKit views and controls those the already accessible.

Let’s start with implementation

So, our contact list application will fetch data from API and store data in view model, data will be populated in view controller. And will be having feature of making favourite and unfavourite. Let’s do this.

  1. Create an project named AccessibilityDemo and setup the folder structure as 👇:
MVVM folder structure
MVVM folder structure

2. Create a structure ContactInfo as model to show in above folder structure.

3. Create another structure ContactListServerResponse as model for handling API response.

4. Create a class ContactListViewModel.swift that will be attached with view controller. view model will be having array of ContactInfo, a method for fetching data from server making rest API call, a methods for updating fav contact.

5. Create view controller ContactListViewController.swift having a table view data for table view will be populate from view model. Having a loading indicator and function for loading and stoping loader.

Download the project till now form here.

Working with accessibility attributes:

Now, run the application and let’s test the accessibility. And open accessibility inspector, start inspecting elements one by one. Like 👇

elements inspection in accessibility inspector
elements inspection in accessibility inspector

Now, we can see inspector focusing complete cell as one element and setting accessibilityLabel with comma separated text, that is text of both labels.
Favourite button is focusable as different, having ic un fav as label . It means image name from assets set as accessibilityLabel (we need to change it). Trait is .button for unselected and .button, .selected for selected one.
To execute action on any button you can click on Perform in Actions section.

Now, firstly make elements accessible individually (in some cases be need it).
Open ContactListTableViewCell.swift file and add the below mentioned code. 👇

overriding accessibilityElements
overriding accessibilityElements

Line #42: enabling image view to be accessible by VoiceOver.
Line #45–54: overriding default implementation of accessible elements for cell.
These elements will be focusable as the same order added in array. For default behaviour of accessibilityElements VoiceOver focuses elements as the hierarchy in xibs or storyboards. VoiceOver reads them from top to bottom in hierarchy.

📣 Define your view/elements hierarchy in xibs and storyboard carefully as this will be default implementation for `accessibilityElements`.

Now, add below mentioned function in same file, and make a call for this function in func configure(withInfo info: ContactInfo) at last. 👇

applying accessibility on button and imageView
applying accessibility on button and

Line #68: providing accessibilityLabel string to be announce when focus is on image view.
Line #70: replace default accessibilityLabel from ic un fav to favourite for favourite button.
Line #71: providing accessibilityHints as per the button’s selected state.

Now, again run and check the attributes got updated as we defined.

Working with audit warnings and fixing:

Now, go to audit (⚠️) section in accessibility inspector. Here we saw a Run Audit button, as you click on this button accessibility inspector will run an audit on screen which is presenting in simulator.

📋 Don’t forget to select simulator in target of accessibility inspector.

After successfully executing audit of screen you may see some warnings like 👇

accessibility audit of screen
accessibility audit of screen

Here we can see two types of warnings, let’s discuss and resolve them.
1. Hit area is too small: our favourite button having 25x25 size as per Apple UI/UX guidelines any button must have area of min 44x44.
So, to resolve this warning just one ContactListTableViewCell.xib and change button height from 25 to 45, width will be changed automatically as our button having hight width ration of 1:1

2. Dynamic Text font sizes are unsupported: it’s warning about, when user will change text size from settings application of iPhone from “Settings app → Accessibility → Display & Text Size → Large Text” and change the value of slider. OR you can change it by going on to settings (⚙️)option of accessibility inspector and change the slider’s value.
So, to resolve this we need to make our label’s font to be adjustable as per content size category. We can set it either in xib by choosing textStyles or programmatically setting textStyles, doing it programmatically copy below mentioned code and paste at last in earlier created applyAccessibility() method.

self.nameLabel.adjustsFontForContentSizeCategory = true
self.infoLabel.adjustsFontForContentSizeCategory = true
self.nameLabel.font = UIFont.preferredFont(forTextStyle: .title3)
self.infoLabel.font = UIFont.preferredFont(forTextStyle: .caption1)

Now, run application and perform Run Audit booooom! (not a magic 😋) all warnings gone.
Let’s test the text size increasing and decreasing functionality 👇.

TextSize changing in accessibility inspector
TextSize changing in accessibility inspector

Okay, so we just used textStyles to achieve text size resizing, what if we need to use our custom fonts.
for using our custom fonts we need to scale our font according to the current contact size category by using font metrics (seems too much confusing 😄). Take a look on below code, paste at last in ContactListTableViewCell.swift

extension UIFont {
/// Scaled and styled version of any custom Font
///
/// - Parameters:
/// - name: Name of the Font
/// - textSize: text szie i.e 10, 15, 20, ...
/// - Returns: The scaled custom Font version with the given size
static func scaledFont(name: String, textSize size: CGFloat) -> UIFont {
guard let customFont = UIFont(name: name, size: size) else {
fatalError("Failed to load the \(name) font.")
}
return UIFontMetrics.default.scaledFont(for: customFont)
}
}

Now, we can use this code to providing our custom font. Copy below code and replace last two lines in applyAccessibility() method.

self.nameLabel.font = UIFont.scaledFont(name: "HelveticaNeue-Bold", textSize: 15.0)self.infoLabel.font = UIFont.scaledFont(name: "HelveticaNeue", textSize: 12.0)

Now, again run application and try changing text size. It’ll work smoothly.
You can use any other font name as you want.

To resize cell height you’ll need to return ‘UITableView.automaticDimension’ in heightForRowAt indexPath method.

Download final project with all changes.

Tips and Tricks

  1. UIButton frame never resize while changing content size category, you need to do it manually but reseting constraints of titleLabel with UIButton. I’ve created a CustomButton class to achieve this. Like 👇
CustomButton class inherited from UIButton

Now, add two buttons on a view, provide font as textStyle of Caption 1 . And assign this class to any one of them.
Run, the code and try to change the text size. You’ll observe our CustomButton getting reframed as content size category is changing.

CustomButton resizing as per content category changes
CustomButton resizing as per content category changes

2. Accessibility Notifications: when any screen changes or getting updated in your application, you’ll need to refocus any specific element than accessibility notification comes in to scene. we need to post a notification that with argument of notification type and element that will be focused. Like:

UIAccessibility.post(notification: .screenChanged, argument: <element to be focused>)

there are different types of notifications i.e. screenChanged, layoutChanged, announcement, pageScrolled, pauseAssistiveTechnology, resumeAssistiveTechnology use as per your requirement.

3. UITableViewHeaderFooterView’s first subview will be always having .header trait, you can not remove it.

4. Don’t be afraid to make custom UI, you can check anytime if VoiceOver is running or not by calling UIAccessibility.isVoiceOverRunning, modify different UI as needed.

5. Last but not least, VoiceOver always reads what it sees on the screen by default, but until you actually didn’t tell it what to announce i.e. 21 km it will announce same as it is, you need to set accessibilityLabel as 21 kilometres away to be announced.

So, let’s end the discussion as all the needed things have been covered.
Now, we are able to implement accessibility in any application. But don’t stop here, as there are lots of things to explore in accessibility.

👩‍💻 !!! HAPPY CODING !!! 👨‍💻

Thank you for reading, please hit the recommend icon if like this collection 😊 . Questions or Doubts? Leave them in the comment, let’s discuss more on them.

--

--