iOS Accessibility in SwiftUI: Create Accessible Charts using Audio Graphs
In this iOS accessibility tutorial, learn how to make charts in your app more accessible by using Audio Graphs. By David Piper.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
iOS Accessibility in SwiftUI: Create Accessible Charts using Audio Graphs
25 mins
Showing Many Data Series
Now that the precipitation chart is more accessible, it's time for the temperature chart.
By adding an Audio Graph for this chart, you'll learn two important differences to the first chart: Presenting a line chart and using many data series in one Audio Graph.
Open TemperatureChart.swift. A lot of what you've implemented in the previous sections already is created:
-
TemperatureChart
implementsAXChartDescriptorRepresentable
. - There are two computed properties,
temperatureChartTitle
andtemperatureChartSummary
. They are similar toprecipitationChartTitle
andprecipitationChartSummary
you've added forPrecipitationChart
. - The extension contains
makeChartDescriptor
, which is required byAXChartDescriptorRepresentable
. It uses the title and summary and combines them with the axes and data series to create the Audio Graph. -
makeXAxisDescriptor
andmakeYAxisDescriptor
define the x- and y-axes. Again, this works similar to how you created axes for the previous chart. But instead of using a categorical and a numerical axes, this chart uses two numerical ones. This is because the x-axis shows the number of days instead of the names of months.
Make the chart visible as an audio graph by adding the following modifiers to the Canvas
:
.accessibilityChartDescriptor(self)
.accessibilityElement(children: .combine)
The interesting part for you to implement is the data series descriptor, which you're going to add now. Replace the contents of makeDataSeriesDescriptor
at the bottom of the extension with the following code:
// 1
var lowTemperatures: [AXDataPoint] = []
var highTemperatures: [AXDataPoint] = []
// 2
for measurement in measurements {
let numberOfDay = Calendar.current.ordinality(
of: .day,
in: .year,
for: measurement.date
) ?? 30
lowTemperatures.append(
AXDataPoint(x: Double(numberOfDay), y: measurement.low.value)
)
highTemperatures.append(
AXDataPoint(x: Double(numberOfDay), y: measurement.high.value)
)
}
return [
// 3
AXDataSeriesDescriptor(
name: "Low Temperatures",
isContinuous: true,
dataPoints: lowTemperatures
),
// 4
AXDataSeriesDescriptor(
name: "High Temperatures",
isContinuous: true,
dataPoints: highTemperatures
)
]
- To create an Audio Graph with more than one data series, you need to return an array of
AXDataPoint
for each data series. Here, you create two arrays, one for low temperatures per day and one for high ones. The user can then choose to either see and hear all data series at once or each one separately. - Populate the lists by looping over
measurements
. For each item you create a newAXDataPoint
for each data series. The x value represents the number of the day in the year. The y value is either the low or the high temperature, depending on the list you add the data point to. - For
PrecipitationChart
you return one single array of data points. But, this time you return two. The first one is the data series for low temperatures. There is an important difference between thisAXDataSeriesDescriptor
and the one you implemented before. You setisContinuous
totrue
instead offalse
. This results in a continuous line graph. - Finally, you create the second
AXDataSeriesDescriptor
. This one represents the high temperatures.
Listening to many Data Series
Build and run the app. Select a weather station and open the temperature tab. If not active yet, turn on VoiceOver and navigate to the Audio Graph details page by focusing on the chart and swiping down. Once you hear Chart details, double-tap the screen.
This is what the Audio Graph looks like for two continuous data series:
Swipe right until VoiceOver focuses Play and double-tap to play the Audio Graph. Again, a vertical line moves from left to right. Both the high and low temperature data sets play at the same time. This already provides some insights — you can hear the low and high temperatures follow a similar path.
But, it can get confusing to hear simultaneously more than one data series. Imagine having three, four or even five data series, perhaps with different paths. No one could understand it.
It's possible to select a specific data series. Above the chart is a button All Series. This means that the graph shows all data series at once and that VoiceOver plays all sounds together. You can change the selection to listen to specific data series.
Swipe left to select the button via VoiceOver. Double-tap the screen to open a context menu, where you can choose which data series to play:
Try it out and select Low Temperatures. Navigate to Play and listen again. This time it's only one tone and it's easier to follow.
Where to Go From Here?
You can download the completed version of the project using the Download Materials button at the top or bottom of this tutorial.
Accessibility is a critical, but often overlooked, element of apps. Audio Graph is an amazing feature that helps people who are blind or have reduced vision. They make charts more accessible, and it's super easy to use. All you need to do is help iOS create an audible representation of your charts data by defining axes and data sets.
If you want to learn more about accessibility and SwiftUI, check out iOS Accessibility in SwiftUI Tutorial Part 1, Part 2 and Part 3.
If you have any questions or comments, please join the forum discussion below!