在 SwiftUI 中實現(xiàn)音頻圖表
前言
在可訪問性方面,圖表是復雜的事物之一。iOS 15 引入了一項名為“音頻圖表”的新功能。
下面我們將學習如何通過使用 accessibilityChartDescriptor 視圖修飾符為任何 SwiftUI 視圖構建音頻表示,呈現(xiàn)類似自定義條形圖視圖或圖像的圖表。
DataPoint 結構體
讓我們從在 SwiftUI 中構建一個簡單的條形圖視圖開始,該視圖使用垂直條形顯示一組數(shù)據(jù)點。
struct DataPoint: Identifiable {
let id = UUID()
let label: String
let value: Double
let color: Color
}
在這里,我們有一個 DataPoint 結構,用于描述條形圖視圖中的條形。它具有 id、標簽、數(shù)值和填充顏色。
BarChartView 結構體
接下來,我們可以定義一個條形圖視圖,它接受一組 DataPoint 結構體實例并將它們顯示出來。
struct BarChartView: View {
let dataPoints: [DataPoint]
var body: some View {
HStack(alignment: .bottom) {
ForEach(dataPoints) { point in
VStack {
RoundedRectangle(cornerRadius: 8, style: .continuous)
.fill(point.color)
.frame(height: point.value * 50)
Text(point.label)
}
}
}
}
}
如上例所示,我們有一個 BarChartView,它接收一組 DataPoint 實例并將它們顯示為水平堆棧中不同高度的圓角矩形。
ContentView 結構體
我們能夠在 SwiftUI 中輕松構建條形圖視圖。接下來讓我們嘗試使用帶有示例數(shù)據(jù)的新 BarChartView。
struct ContentView: View {
@State private var dataPoints = [
DataPoint(label: "1", value: 3, color: .red),
DataPoint(label: "2", value: 5, color: .blue),
DataPoint(label: "3", value: 2, color: .red),
DataPoint(label: "4", value: 4, color: .blue),
]
var body: some View {
BarChartView(dataPoints: dataPoints)
.accessibilityElement()
.accessibilityLabel("Chart representing some data")
}
}
在這里,我們創(chuàng)建了一組 DataPoint 實例的示例數(shù)組,并將其傳遞給 BarChartView。我們還為圖表創(chuàng)建了一個可訪問元素,并禁用了其子元素的可訪問性信息。為了改進圖表視圖的可訪問性體驗,我們還添加了可訪問性標簽。
最后,我們可以開始為我們的條形圖視圖實現(xiàn)音頻圖表功能。音頻圖表可以通過旋鈕菜單獲得。要使用旋鈕,請在 iOS 設備的屏幕上旋轉兩個手指,就像您在撥盤。VoiceOver 會說出第一個旋鈕選項。繼續(xù)旋轉手指以聽到更多選項。松開手指選擇音頻圖表。然后在屏幕上上下滑動手指以導航。
音頻圖表允許用戶使用音頻組件理解和解釋圖表數(shù)據(jù)。VoiceOver 在移動到圖表視圖中的條形時播放具有不同音調(diào)的聲音。VoiceOver 對于更大的值使用高音調(diào),對于較小的值使用低音調(diào)。這些音調(diào)代表數(shù)組中的數(shù)據(jù)。
實現(xiàn)協(xié)議
現(xiàn)在,我們可以討論在 BarChartView 中實現(xiàn)此功能的方法。首先,我們必須創(chuàng)建一個符合 AXChartDescriptorRepresentable 協(xié)議的類型。AXChartDescriptorRepresentable 協(xié)議只有一個要求,即創(chuàng)建 AXChartDescriptor 類型的實例。AXChartDescriptor 類型的實例表示我們圖表中的數(shù)據(jù),以 VoiceOver 可以理解和交互的格式呈現(xiàn)。
extension ContentView: AXChartDescriptorRepresentable {
func makeChartDescriptor() -> AXChartDescriptor {
let xAxis = AXCategoricalDataAxisDescriptor(
title: "Labels",
categoryOrder: dataPoints.map(\.label)
)
let min = dataPoints.map(\.value).min() ?? 0.0
let max = dataPoints.map(\.value).max() ?? 0.0
let yAxis = AXNumericDataAxisDescriptor(
title: "Values",
range: min...max,
gridlinePositions: []
) { value in "\(value) points" }
let series = AXDataSeriesDescriptor(
name: "",
isContinuous: false,
dataPoints: dataPoints.map {
.init(x: $0.label, y: $0.value)
}
)
return AXChartDescriptor(
title: "Chart representing some data",
summary: nil,
xAxis: xAxis,
yAxis: yAxis,
additionalAxes: [],
series: [series]
)
}
}
我們所需做的就是符合 AXChartDescriptorRepresentable 協(xié)議,并添加 makeChartDescriptor 函數(shù),該函數(shù)返回 AXChartDescriptor 的實例。
首先,我們通過使用 AXCategoricalDataAxisDescriptor 和 AXNumericDataAxisDescriptor 類型定義 X 軸和 Y 軸。我們希望在 X 軸上使用字符串標簽,這就是為什么我們使用 AXCategoricalDataAxisDescriptor 類型的原因。在線圖的情況下,我們將在兩個軸上都使用 AXNumericDataAxisDescriptor 類型。
實現(xiàn)線圖
接下來,我們使用 AXDataSeriesDescriptor 類型定義圖表中的點。有一個 isContinuous 參數(shù),允許我們定義不同的圖表樣式。例如,對于條形圖,它應該是 false,而對于線圖,它應該是 true。
struct ContentView: View {
@State private var dataPoints = [
DataPoint(label: "1", value: 3, color: .red),
DataPoint(label: "2", value: 5, color: .blue),
DataPoint(label: "3", value: 2, color: .red),
DataPoint(label: "4", value: 4, color: .blue),
]
var body: some View {
BarChartView(dataPoints: dataPoints)
.accessibilityElement()
.accessibilityLabel("Chart representing some data")
.accessibilityChartDescriptor(self)
}
}
作為最后一步,我們使用 accessibilityChartDescriptor 視圖修飾符將符合 AXChartDescriptorRepresentable 協(xié)議的實例設置為描述我們圖表的實例。
示例截圖:
總結
音頻圖表功能對于視力受損的用戶來說是一項重大改進。音頻圖表功能的好處是,可以將其用于任何您想要的視圖,甚至包括圖像視圖。只需創(chuàng)建 AXChartDescriptor 類型的實例。