ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
データリッチなAppにおけるVoiceOver体験の最適化
Accessibility Custom Content APIを使用して複雑なデータをVoiceOverで表示する方法を確認しましょう。アクセシビリティ情報を簡潔な形で、必要なときにだけ提供する方法を紹介します。AXCustomContentを統合して、VoiceOverの有効化を希望するユーザが、データリッチなAppを効率的にナビゲーションできるようにする方法を紹介します。 このセッションを最大限活かしていただくためには、一般的なアクセシビリティの原則と、SwiftとSwiftUIで使用できるVoiceOverアクセシビリティAPIを理解していることが推奨されます。
リソース
関連ビデオ
WWDC23
WWDC21
-
ダウンロード
こんにちは Nandini Sundara Ramanです 今日は AXCustomContent APIを使い データ量の多いAppで VoiceOverの体験を カスタマイズする方法を ご紹介します VoiceOverはApple のスクリーンリーダーで 画面が見えない場合であっても Appleのデバイスで 操作することができます VoiceOverは 画面をタッチすることで 指の下にある項目が 読み上げられます そして スワイプなどの 簡単なジェスチャーで インターフェイスを 操作します そこで 私が作った ワンワンショップという シンプルなAppを 紹介します ここでは それぞれの犬の 詳細な説明が テーブルビューで 表示されています そしてVoiceOverユーザー はリストをスワイプして 犬のショップを探索 することができるのです それでは このAppの VoiceOver体験を 簡単にご紹介します ベイリー ビーグル犬 楽天的 優れた狩猟犬であり 忠実な友達 人気度 1位 年齢 3歳 体重 25ポンド 体高 14インチ ウィンストン パグ犬 愛情深く 知的 愛情深い 忠実で魅力的 遊び心があり 茶目っ気がある 人気度 2位 年齢 3歳 体重 14ポンド 体高 10インチ おお これはVoiceOverが それぞれの犬を読み取った 大量のデータでした ここでは左上から 右下に向かって セルのすべての内容が 読み上げられます VoiceOverでインター フェイスを操作するとき データが多すぎると ユーザーの 認知負荷が高まり Appが 操作しづらくなります また データが少なすぎると Appが満足のいかない ものになってしまいます 両極端では困るので ここでバランスを取るのは 難しいかもしれません なぜなら ユーザーによって Appを使用する際に 必要とする情報が異なる 可能性があるからです このバランスを 実現するために Accessibility Custom Content APIを用意しました Accessibilityフレームワーク内の このクラスとプロトコルは すべてのプラットフォームで 利用できます
このAPIは 複雑な データをVoiceOverで 表現する際の 一般的な問題を解決し 入手可能な情報を 欲しい情報だけ ユーザーに提供します
このAPIを使えば ユーザーが必要なときに 必要なコンテンツだけを 提示させる便利な技術を 利用することができます ではデータが豊富なAppで AXCustomContent API がどのように機能するかを 見てみましょう そのために まず私のAppが どのように見えるかを お見せしたいと思います AXCustomContent API が実装されています ベイリー ビーグル犬 他詳細あり はい! お聞きの通りです VoiceOverは このセルで 利用できるコンテンツが 増えたことを伝えました これはMore Content ローターを使って このセルのさらなる情報に アクセスできる ことを意味しています Voiceoverローターは ユーザーがAppを 迅速かつ効率的に 操作できるようにします さまざまな組み込まれた 用途があります VoiceOverの 言語設定や 発話速度の調整など また Webページの リンク間の移動なども ここでは More Content ローターを使うと VoiceOverのカーソルの 下にある追加情報の要素を いろいろ見て回る ことができます iOSデバイスで VoiceOverを使用して MoreContentローターに アクセスするには ダイヤルを回すように 2本の指を画面に当て 目的のローターオプションに 到達するまで 回してください これが MoreContentローターです 詳細 そして 下または上に スワイプすると VoiceOverカーソルの下の 次または前の 追加コンテンツに 移動します さて セルを スワイプしていくと VoiceOverは さらに 追加情報を 提示します 年齢 3歳 人気度 1位 体重 25ポンド 体高 14インチ 楽天的 優秀な狩猟犬 忠実な友達 説明 同じAppのmacOS版に AXCustomContent API を実装した場合の動作を 見てみましょう ベイリー ビーグル犬 他詳細あり VoiceOverのカーソルが より詳しい情報を持つ 要素の上に来たら VO + コマンド + / でローターを起動でき そのカスタムコンテンツを 表示させます
その他の コンテンツメニュー 5項目 年齢 3歳 人気度 1位 体重 25ポンド 体高 14インチ 説明 楽天的 優秀な狩猟犬 そして忠実な友達 iOSでは VoiceOver要素が 追加情報があるときに 通知を受け取るには VoiceOverの環境設定で Verbosityを開きます
Verbosityで More Contentを選択します
そしてヒントを話すか 音を再生するかを 選択します また レベルを変更すると 追加情報が配信された ときに通知されます 同様に macOSでも Verbosityを設定して 追加情報が配信されたときの 通知を受け取れます VoiceOverのユーティリティ 環境設定でこれができます ではワンワンショップApp をAXCustom Content API に対応させる方法を ご紹介します ここでは 犬のTableViewCellに 犬の写真に対する 変数を設定しています 名前 犬種 説明 人気度 年齢 体重 体高
AXCustomContent API を操作するために まず最初にAccessibility フレームワークをインポート
次に 追加して実装する 必要があります TableViewCellのAXCustom ContentProviderプロトコルです
プロトコルメソッドを実装 する前にアクセシビリティ ラベルプロパティを 無効にしましょう そして 犬の名前と犬種だけ を返すようにしました ここではそれが最も関連性の 高い詳細情報だからです
次に AXCustomContent Providerプロトコルメソッド AXCustomContent オブジェクトの配列を持つ accessibilityCustomContent を実装します ここで AXCustomContent オブジェクトは ローカライズされた文字列の キーと値のペアです
ここでは 「Description」という 文字列をラベルとして持つ 説明用のAXCustomContent オブジェクトを作成します そしてDescriptionの テキスト値を AXCustomContent変数の 値として作成します また 人気 年齢 体重 体高などの AXCustomContent変数も 作成します そしてユーザーがVoiceOver に求める順序で これら AXCustomContentの 多くの情報を提示します それでは AXCustomContentProvider プロトコルをTableViewCell に実装したあと VoiceOverの操作性が どのように 改善されたかを 見てみましょう ベイリー ビーグル犬 他詳細あり 人気度 1位 年齢 3歳 体重 25ポンド 体高 14インチ 楽天的 優秀な狩猟犬 そして忠実な友達 説明 このリストを閲覧しようと しているユーザーにとって 犬の年齢は その犬を 飼いたいと思ったときに 重要な情報に なるかもしれません 現在その情報はMoreContent ローター内にあります AXCustomContent変数には この問題を解決するための 「importance」という プロパティがあります このプロパティの値を 「高」に設定すれば VoiceOverが要素に 焦点を当てたときに 常にコンテンツが表示 されるようになります 追加の要素を何度も 見ることはありません VoiceOverで 犬の年齢が 常に提示されるように カスタムコンテンツの 年齢の項目で importanceプロパティを 「高」に設定します
今の設定で犬の年齢が 常にVoiceOverによって 読み上げられていることが わかります ベイリー ビーグル犬 年齢 3年 他詳細あり この年齢情報は More Content ローターでも ご覧いただけます 今年の新機能として SwiftUIでも 同じ機能を サポートしています 私たちは アクセシビリティの CustomContentの変更を 設定することができるのです SwiftUIの カスタムビューでは ラベルと値の両方の変数に 変更可能なテキストを伝え 必要に応じて importanceプロパティを 設定します この方法は カスタムコンテンツの値が 一箇所に追加され 後の階層では 操作されないような場合に 有効です これをDogCell Viewに 実装するには まず説明文に アクセシビリティの 隠し属性を設定します また犬の人気度 年齢 体重 身長を含むHStack上で これらが自動的に DogCellの アクセシビリティ ラベルに 検出されないようにします 次にアクセシビリティの CustomContent の属性を設定し importanceを「high」で 設定している年齢 人気度 体重 体高 と説明を設定します custom contentの値を Swift UIの階層内の 複数の場所で 操作したい場合 AccessibilityCustomContentKey のextensionを 作成することでキーの再定義 を避けることができます これで 変更可能なテキスト 文字列を再作成することなく そのキーの値を 更新または削除できる ようになります DogCellの例では AccessibilityCustom ContentKeyの extensionを作成し カスタム キーの1つとして 年齢を追加しています DogCell本体の VStackには 文字列キーを使わずに AccessibilityCustom ContentKey「年齢」で accessibilityCustom Content属性を追加しました 最後に データ量の多い AppのVoiceOver体験を より快適にするために 試してもらいたい ことがあります まず最初に視覚的にデータの 多い部分を特定します VoiceOverをオンにして VoiceOverカーソルの下の 情報が細かすぎるか どうかを判断してください 細か過ぎる場合は AXCustomContentProviderの プロトコルを実装します 補足情報をaccessibility CustomContentに 移動することを 検討してください 常にユーザーに 提示したい情報は importanceプロパティを 「high」に設定します VoiceOverユーザーのために 希望する分野の情報を 利用できるオプションを 用意しました 必要なときだけに情報が 表示されるようにすれば Appのアクセシビリティが 大幅に向上します そこで今回 VoiceOver ユーザーの皆様に より良い体験を していただくために どのように 組み込むことができるかを 見てみることを 強くお勧めします AXCustomContent APIsを データが豊富なAppに! 皆さん このセッション をご覧いただき 本当に ありがとうございました またお目にかかりましょう! [パーカッシブな音楽]
-
-
5:03 - Accessibility Custom Content API Sample
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 { } } }
-
6:49 - Accessibility Custom Content API Sample with importance property
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 { } } }
-
7:47 - Accessibility Custom Content API Basic Sample in SwiftUI
struct SampleView: View { var body: some View { VStack { Text(name) Text(description) } .accessibilityElement(children: .combine) .accessibilityCustomContent("Description", description, importance: .high) } }
-
8:10 - Accessibility Custom Content API Sample in Swift UI
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) } }
-
8:57 - Accessibility Custom Content API Sample with AccessibilityCustomContentKey in SwiftUI
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) } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。