WWDC Quick Look 💓 By SwiftGGTeam
Tailor the VoiceOver experience in your data-rich apps

Tailor the VoiceOver experience in your data-rich apps

元の動画を見る

ハイライト

Apple は、Accessibility Custom Content API を提供しています。これにより、データ集約型のインターフェイスがコア情報を VoiceOver に渡して直接読み取り、ユーザーがオンデマンドでアクセスできるように補足情報を More Content ローターに入れることができます。

主な内容

リスト セルは、犬の写真、名前、品種、性格の説明、人気、年齢、体重、身長など、非常に普通に見えます。

デフォルトでは、VoiceOver はこれらをインターフェイスの順序で読み取ります。ユーザーが最初の犬にスワイプすると、名前、品種、詳しい説明、ランキング、年齢、体重、身長が読み上げられます。次の犬にスライドして、もう一度繰り返します。

問題は情報密度です。読み上げが多すぎる場合、ユーザーは音声の長いリストから重要なポイントを見つけなければなりません。読む量が少なすぎると、ユーザーは完全な情報を得ることができません。ユーザーによって関心のある情報は異なります。最初に年齢を見る人、最初に体重を見る人、リストにざっと目を通すだけの人もいます。

Apple は、アクセシビリティ フレームワークでアクセシビリティ カスタム コンテンツ API を提供しています。開発者は要素を 2 つのレイヤーに分割できます。アクセシビリティ タグは犬の名前や品種などのコア コンテンツのみを保持します。詳細フィールドにはカスタム コンテンツが配置され、それが More Content ローターに渡されます。

結果は簡単です。 VoiceOver がセルにフォーカスすると、最初に「ベイリー、ビーグル。もっと多くのコンテンツが利用可能です。」と表示されます。ユーザーが詳細を聞きたい場合は、[その他のコンテンツ] ローターを開き、年齢、人気、体重、身長、説明を 1 つずつ参照します。

この機能は、データ集約型インターフェイスのリズムの問​​題を解決します。デフォルトの読み上げは短く保たれていますが、詳細は引き続きアクセス可能で、いつ聞くかをユーザーが決定します。

##詳細

More Content ローターを使用して補足情報を伝達する

01:50

Accessibility Custom Content API は Accessibility フレームワークによって提供されており、講演ではすべての Apple プラットフォームで利用できると述べられています。その目標は、支援技術が「適切な量」の情報を提示できるようにすることです。

iOS では、ユーザーは VoiceOver ローターを [その他のコンテンツ] に切り替え、上下にスワイプして補足コンテンツを参照します。 macOS では、VoiceOver カーソルを要素の上に置いた後、次のコマンドを使用できます。VO + Command + /[その他のコンテンツ] メニューを開きます。

主要な API は次のとおりです。AXCustomContentProviderそしてAXCustomContent

import UIKit
import Accessibility

class DogTableViewCell: UITableViewCell, AXCustomContentProvider {

    var coverImage: UIImageView!
    var name: UILabel!
    var type: UILabel!
    var desc: UILabel!
    var popularity: UILabel!
    var age: UILabel!
    var weight: UILabel!
    var height: UILabel!

    override var accessibilityLabel: String? {
        get {
            guard let nameLabel = name.text else { return nil }
            guard let typeLabel = type.text else { return nil }
            return nameLabel + ", " + typeLabel
        }
        set { }
    }

    var accessibilityCustomContent: [AXCustomContent]! {
        get {
            let notes = AXCustomContent(label: "Description", value: desc.text!)
            let popularity = AXCustomContent(label: "Popularity", value: popularity.text!)
            let age = AXCustomContent(label: "Age", value: age.text!)
            let weight = AXCustomContent(label: "Weight", value: weight.text!)
            let height = AXCustomContent(label: "Height" , value: height.text!)
            return [age, popularity, weight, height, notes]
        }
        set { }
    }
}

キーポイント:

  • import Accessibilityアクセシビリティフレームワークの導入、AXCustomContentそしてAXCustomContentProviderここから。
  • DogTableViewCell成し遂げるAXCustomContentProvider、このセルがカスタム補助コンテンツを提供できることを示します。
  • accessibilityLabel返品のみnameそしてtypeVoiceOver がフォーカスしたときに最も重要な情報を最初に読み上げるようにします。
  • AXCustomContent(label:value:)たとえば、フィールドをキーと値のペアにします。"Age"そしてage.text!
  • accessibilityCustomContent配列を返します。配列の順序によって、VoiceOver が [その他のコンテンツ] ローター内のフィールドをレンダリングする順序が決まります。

重要性を利用して重要な情報を事前に読む

06:49

一部の補足情報はデフォルトでも読み上げられるはずです。スピーチの例は犬の年齢でした。養子縁組を検討している人にとって、年齢は意思決定の場となる可能性があり、ローターの中に隠れると運営コストが増加します。

AXCustomContent持っているimportance財産。に設定します.highその後、VoiceOver は要素にフォーカスしたときにこのフィールドを直接読み取り、引き続き [その他のコンテンツ] ローターに表示されます。

import UIKit
import Accessibility

class DogTableViewCell: UITableViewCell, AXCustomContentProvider {

    var coverImage: UIImageView!
    var name: UILabel!
    var type: UILabel!
    var desc: UILabel!
    var popularity: UILabel!
    var age: UILabel!
    var weight: UILabel!
    var height: UILabel!

    override var accessibilityLabel: String? {
        get {
            guard let nameLabel = name.text else { return nil }
            guard let typeLabel = type.text else { return nil }
            return nameLabel + ", " + typeLabel
        }
        set { }
    }

    var accessibilityCustomContent: [AXCustomContent]! {
        get {
            let notes = AXCustomContent(label: "Description", value: desc.text!)
            let popularity = AXCustomContent(label: "Popularity", value: popularity.text!)
            let age = AXCustomContent(label: "Age", value: age.text!)
            age.importance = .high
            let weight = AXCustomContent(label: "Weight", value: weight.text!)
            let height = AXCustomContent(label: "Height" , value: height.text!)
            return [popularity, age, weight, height, notes]
        }
        set { }
    }
}

キーポイント:

  • let age = AXCustomContent(label: "Age", value: age.text!)年齢フィールドを作成します。
  • age.importance = .high年齢を高優先度としてマークします。
  • セルにフォーカスすると、VoiceOver が犬の名前、品種、年齢を読み上げます。
  • return [popularity, age, weight, height, notes]ローターへのアクセスを維持します。

SwiftUI にカスタム コンテンツを追加する

07:47

WWDC21 では、同じ機能が SwiftUI にも提供されます。最小限のアプローチはビューで使用することですaccessibilityCustomContent修飾子、ラベル、値、およびオプションを渡しますimportance

struct SampleView: View {
    var body: some View {
        VStack {
            Text(name)
            Text(description)
        }
        .accessibilityElement(children: .combine)
        .accessibilityCustomContent("Description", description, importance: .high)
    }
}

キーポイント:

  • VStackがあるText(name)そしてText(description)2 段落のテキスト。
  • .accessibilityElement(children: .combine)子要素を 1 つのアクセシビリティ要素に結合します。
  • .accessibilityCustomContent("Description", description, importance: .high)説明フィールドにカスタム コンテンツを追加します。
  • importance: .high要素にフォーカスがあるときに、この説明が VoiceOver によって直接表示されるようにします。

SwiftUI セルのデフォルトの読み取り内容を整理する

08:10

SwiftUI は自動的に起動します。Textアクセシビリティコンテンツを推測します。データ集約型のセルでは、これにより説明と各数値フィールドが自動的に読み取りキューに入ります。

音声の処理方法は次のとおりです。最初に補足フィールドを使用します。accessibilityHidden(true)、デフォルトのラベルに入らないようにするため。次に同じデータを渡しますaccessibilityCustomContentもう一度追加してください。

import SwiftUI
import Accessibility

struct DogCell: View {
    var dog: Dog
    var body: some View {
        VStack {
            HStack {
                dog.image
                    .resizable()
                VStack(alignment: .leading) {
                    Text(dog.name)
                        .font(.title)
                    Spacer()
                    Text(dog.type)
                        .font(.body)
                    Spacer()
                    Text(dog.description)
                        .fixedSize(horizontal: false, vertical: true)
                        .font(.subheadline)
                        .foregroundColor(Color(uiColor: UIColor.brown))
                        .accessibilityHidden(true)
                }
                Spacer()
            }
            .padding(.horizontal)
            HStack(alignment: .top) {
                VStack(alignment: .leading) {
                    HStack {
                        Text(dog.popularity)
                        Spacer()
                        Text(dog.age)
                        Spacer()
                        Text(dog.weight)
                        Spacer()
                        Text(dog.height)
                    }
                    .foregroundColor(Color(uiColor: UIColor.darkGray))
                    .accessibilityHidden(true)
                }
                Spacer()
            }
            .padding(.horizontal)
            Divider()
        }
        .accessibilityElement(children: .combine)
        .accessibilityCustomContent("Age", dog.age, importance: .high)
        .accessibilityCustomContent("Popularity", dog.popularity)
        .accessibilityCustomContent("Weight", dog.weight)
        .accessibilityCustomContent("Height", dog.height)
        .accessibilityCustomContent("Description", dog.description)
    }
}

キーポイント:

  • Text(dog.description)インターフェイスにはまだ表示されますが、.accessibilityHidden(true)デフォルトの測定値に入らないようにします。
  • 含むpopularityageweightheightHStackまた、VoiceOver がすべての値を一度に読み取らないようにするためにも非表示にします。
  • .accessibilityElement(children: .combine)全体を置くVStackフォーカス可能な要素として。
  • .accessibilityCustomContent("Age", dog.age, importance: .high)Age をデフォルトで読み上げるようにし、More Content ローターに残しておきます。
  • 次の 4 つ.accessibilityCustomContent人気、体重、身長、説明をローターに入力します。

AccessibilityCustomContentKey を使用してキーを再利用する

08:57

同じカスタム コンテンツ値が SwiftUI 階層内で複数回更新または削除された場合、講演では、AccessibilityCustomContentKey拡大。これにより、キーを再利用でき、ローカライズされた文字列を別の場所に繰り返し書き込む必要がなくなります。

import SwiftUI
import Accessibility

extension AccessibilityCustomContentKey {
    static var age: AccessibilityCustomContentKey {
        AccessibilityCustomContentKey("Age")
    }
}

struct DogCell: View {
    var dog: Dog
    var body: some View {
        VStack {
            HStack {
                dog.image
                    .resizable()
                VStack(alignment: .leading) {
                    Text(dog.name)
                        .font(.title)
                    Spacer()
                    Text(dog.type)
                        .font(.body)
                    Spacer()
                    Text(dog.description)
                        .fixedSize(horizontal: false, vertical: true)
                        .font(.subheadline)
                        .foregroundColor(Color(uiColor: UIColor.brown))
                        .accessibilityHidden(true)
                }
                Spacer()
            }
            .padding(.horizontal)
            HStack(alignment: .top) {
                VStack(alignment: .leading) {
                    HStack {
                        Text(dog.popularity)
                        Spacer()
                        Text(dog.age)
                        Spacer()
                        Text(dog.weight)
                        Spacer()
                        Text(dog.height)
                    }
                    .foregroundColor(Color(uiColor: UIColor.darkGray))
                    .accessibilityHidden(true)
                }
                Spacer()
            }
            .padding(.horizontal)
            Divider()
        }
        .accessibilityElement(children: .combine)
        .accessibilityCustomContent(.age, dog.age, importance: .high)
        .accessibilityCustomContent("Popularity", dog.popularity)
        .accessibilityCustomContent("Weight", dog.weight)
        .accessibilityCustomContent("Height", dog.height)
        .accessibilityCustomContent("Description", dog.description)
    }
}

キーポイント:

  • extension AccessibilityCustomContentKey静的属性をカスタム コンテンツ キーに追加します。
  • AccessibilityCustomContentKey("Age")再利用可能な年齢キーを作成します。
  • .accessibilityCustomContent(.age, dog.age, importance: .high)文字列の代わりにキー オブジェクトを使用します。
  • キーを再利用することにより、同じ項目を階層内の他の場所で更新または削除できます。

重要なポイント

  • 作業方法: 商品リストの「コア情報 + 詳細パラメーター」の VoiceOver 構造を作成します。 実行する価値がある理由: 製品カードには通常、価格、仕様、在庫、プロモーション、説明が含まれており、デフォルトで読み上げると長すぎる傾向があります。アクセシビリティ カスタム コンテンツを使用すると、詳細コンテンツ ローターに仕様と説明を入力できます。 開始方法: セルを実装してみましょうAXCustomContentProvideraccessibilityLabel製品名と価格のみが保持され、仕様フィールドはAXCustomContent(label:value:)戻る。

  • 対処方法: ペットの養子縁組、住宅リスト、中古車など、フィルタリングされたリストに対して優先度の高いフィールドを設定します。 実行する価値がある理由: 年齢、地域、走行距離などのフィールドは選択に直接影響するため、ユーザーは音を聞くために毎回ローターを開ける必要はありません。 開始方法: キー フィールドを作成するAXCustomContent、設定importance = .highをクリックし、VoiceOver がフォーカスされているときの発話順序を確認します。

  • 内容: SwiftUI 複合カードのビジュアル テキストとアクセシビリティ テキストを別々に維持します。 実行する価値がある理由: カードはリッチなタイポグラフィーを引き続き表示でき、VoiceOver はデフォルトでコア コンテンツのみを読み取り、補足フィールドは渡されます。accessibilityCustomContent供給。 開始方法: 説明とパラメータ領域に追加します.accessibilityHidden(true)、外容器に使用.accessibilityElement(children: .combine)そして何度も.accessibilityCustomContent

  • 内容: 繰り返し更新されるフィールドを定義します。AccessibilityCustomContentKey実行する価値がある理由: 親ビューとサブビューで同じフィールドを設定、更新、または削除することができます。キーを再利用すると、文字列の重複を減らすことができます。 開始方法: 拡張機能AccessibilityCustomContentKey、作成するstatic var、 また.accessibilityCustomContent("Age", ...)に変更します.accessibilityCustomContent(.age, ...)

関連セッション

コメント

GitHub Issues · utterances