ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
iOS Appにおけるフルキーボードアクセスのサポート
iPhoneとiPadは、タッチ操作の変更、スイッチコントロール、フルキーボードアクセスなど、運動機能に障害のある方のためのさまざまな入力モードをサポートしています。ここでは、キーボード入力のみでデバイスを操作する方法について、実際の例を使って主要なAPIを紹介します。また、フルキーボードアクセスをAppにインテグレーションする際に、運動機能のアクセシビリティをサポートするためのベストプラクティスを紹介します。
リソース
関連ビデオ
WWDC22
WWDC21
-
ダウンロード
♪ (iOS Appにおける フルキーボードアクセスのサポート)
こんにちはSommer Panageです 今日は iOSの「フルキーボードアクセス」 についてお話させていただきます フルキーボードアクセスは 運動機能に障害のあるお客様のための機能です 今日はまず iOSでのモーターアクセシビリティ全般について 簡単に説明させていただきます その後フルキーボードアクセスと 特にiPadでユーザーにもたらす すべての機能について 詳しく見ていきます 最後にキーボードユーザーをサポートする上で 開発者がAppを構築する際に 留意すべき主要なAPIと 原則について説明します まず モーターアクセシビリティに ついて復習しましょう iOS用のアクセシブルなAppの 開発について議論するとき 私たちは すべてのユーザーを 念頭に置きたいと考えています アクセシビリティについては VoiceOverの観点から 目の不自由な人のための技術として 語られることが多いですね しかし ソフトウェアが 運動機能に障害のある人にも対応 できるようにすることは重要です 運動機能に障害のあるといってもその範囲は広く iOSデバイスの使い方に様々な面で影響を与えます ある人は可動域に制限があるかもしれませんし また 震えなどで画面に触れることができないなど より細かい運動機能に障害のある 人もいるかと思います 運動機能障害の程度に応じて キーボード ジョイスティック ボタンなどの外部ハードウェアを介して デバイスを操作する方が簡単 あるいは必要であると考える人も多くいます iOSには 運動機能に障害のある人がデバイスを シームレスに使えるようにするための 数多くの支援技術が用意されています 例えば ハードウェアの操作や マルチタッチジェスチャーが 苦手な人のために AssistiveTouchがあります AssistiveTouchは画面上のメニューを使用して これらの操作をシンプルなシングル タップで行えるようにします スイッチコントロールは運動能力が低い人でも 1つまたは複数の外部スィッチやボタンを使って iOSデバイスを操作できるようにします そしてもちろん 声だけでiOSデバイスを操作できる ボイスコントロールもあります そして 最新のモーターテクノロジーの1つである フルキーボードアクセスをご紹介します iOS 9以降 iOSはキーボードを サポートしてきましたが それは 補助的な入力手段でした iOS 13.4.1でリリースされた フルキーボードアクセスにより お客様は100%キーボードを使って デバイスを操作できるようになりました AssistiveTouchとスイッチコントロールの 中間的な機能で 画面をタッチするのに十分な 手先の器用さを持ち合わせていない人でも 必ずしも外部スィッチを使用する必要はなく また使用したいとも思わない人に適しています また 言葉を話さない人や言語障害のある人 あるいは音声コントロールを使用することが 困難な環境にいる人のために 音声コントロールの代替手段を提供します フルキーボードアクセスは片手用キーボードや この人間工学に基づいたスプリットキーボードなど カスタムキーボードや アクセシブルなキーボードレイアウトに 依存している人に最適です フルキーボードアクセスは タッチスクリーンを使わずに 真のiOS体験を提供するために 基本的なキーボード入力に 数多くの機能を追加しています また フルキーボードアクセスには 画面上のすべての要素に アクセスできるナビゲーションコマンド インタラクションコマンド ドラッグ&ドロップなどの ジェスチャーモードも用意されています これらのコマンドは全てTabキーを 修飾キーとして使用します しかし これらのコマンドは 異なるキーの組み合わせを 好む人のために完全にカスタマイズ できるようになっています それでは フルキーボードアクセスを使って iPadでどのように操作するかを見てみましょう まず 矢印キーを使って「Notes」Appに移動し Spaceキーで起動します そこから Tabで新しいノートを作成し すぐに編集することができます バージョン2については「Shape Shuffle」という Appの1つからメモを取ろうと思います
iPadに最適なものにしましょう
編集が終わったら Control+Tabで編集モードを解除できます 古いメモを削除したい時は Tab+Zでアクションのリストを表示します そして 矢印とSpaceを使ってメモを削除します さて もう1つ新しいメモを作りたいとしましょう もう1度 タブで「Create Note」 ボタンをクリックするか Tab+Fで検索機能を使います そして「new」と入力すればOKです さて フルキーボードアクセスと その使い方については 理解していただけたと思いますが 次はApp開発者として キーボードユーザーに最高の体験をしてもらうには どうすればいいのかを考えてみましょう 2020年 スイッチコントロールについて お話ししましたが 子供たちが形や色 数を学ぶための 楽しいゲームを開発しました 私たちは共に このAppをアクセシブルにしました 今年 私はiPad用のShape Shuffleを改訂し フルキーボードアクセスとの相性の良さを 確認することにしました Shape Shuffleを見たことがない方もご安心ください ここで簡単にご説明をします 各レベルでプレイヤーは次のような プロンプトを受け取ります 黄色い四角が2つ そして 下にあるカードをタップして 必要な3枚のカードを見つけなければなりません ここでは 2つのオブジェクトが描かれたカード 正方形のカードそして黄色のカードです 正解のカードをダブルタップすると 次のレベルに進みます レベルが上がれば上がるほど プロンプトも難しくなります ちょうど2つ見つけたので ダブルタップしてボードに追加し 引き続き黄色と正方形のカードを探します もし そのカードが正しいかどうか分からない時は 長押ししてピンで留めておけば 後で戻ることができます ここでは 左下の2枚をピンで留めておきます そうすれば 戻ってきた時に最終的な選択をして このレベルを倒すことができます やりました! では ゲームプレイビューでキーボードを使って 別のラウンドをプレイした時の 動作を見てみましょう TabキーとSpaceキーを押して みると上手くいっているようです Tabキーでカードの間を移動し Spaceキーでカードをめくることができます では 三角形のカードを追加したり 固定したりしてみましょう Tab+Zを押してアクションメニューを表示しますが 何のアクションも表示されません さて 追加や固定といった ゲーム内の一般的なアクションを ユーザーが素早く行えるように するには 2つの方法があります まず カスタムアクションを使って解決する方法です カスタムアクションは 多くの支援技術に対応できる点で優れています 何かにカスタムアクションを追加すると VoiceOverスイッチコントロール フルキーボードアクセスに表示されます カスタムアクションはTab+Zを 押した時に表示されます ここでは 追加したいアクションのために UIAccessibilityCustomActionを作成し それをカードビューの accessibilityCustomAction配列に 設定するだけでよいのです また 画像を追加するのもいいでしょう これらの画像はフルキーボード アクセスは表示されませんが スイッチコントロールでは表示されます カスタムアクションを追加したUIはこんな感じです Tab+Zを押すと カードを追加したり ピン留めしたりするための 素敵なポップオーバーが表示されます カスタムアクションはアクセシビリティ機能を 使っている人にとっては素晴らしい機能ですが ここでは別の素晴らしい アプローチを取ることができます カスタムキーボードショートカットを 追加することができます カスタムキーボードショートカットの優れた点は フルキーボードアクセスを 利用しているユーザーだけでなく フルキーボードアクセスを 有効にしていないデバイスで キーボードを使用している ユーザーにも機能することです アクセシビリティの観点からも良い ですしパワーユーザーにも最適です キーボードショートカットの一覧を表示するには Commandキーを長押しする必要があります キーボードショートカットについては 今年の講義 「iPad Appを次のレベルに」でご紹介します 今日はMac Catalyst 13で 新たに導入され iOSとiPadOS 15にも搭載された このAPIをどのように 利用できるのか簡単に紹介します AppDelegateでbuildMenuを オーバーライドすることで キーコマンドを設定できます ここでは 2つのUIキーコマンドを作成しています 1つはaddアクション用 もう1つはpinアクション用です Commandを押したときに キーコマンドHUDに表示されるものなので discoverabilityの タイトルを忘れずに追加して下さい 次に 「gameplay」と 名付けた新しいUIメニューを作り 新しいコマンドを「children」で渡します 最後に このメニューをメニュービルダーに挿入して 終わりです これらのアイテムは 実際に カードが選択されている時のみ HUDでアクティブになるようにしたいので GameViewControllerでcanPerformActionを オーバーライドして実際に カードが選択されている時のみ これらのアイテムを表示するようにしました Commandキーを押しながらカードを選択している時の ゲームの様子は こんな感じです ここで フルキーボードアクセス対応の開発における 重要な原則を強調したいと思います ユーザーの効率性を高めるために すべての一般的なアクションにカスタムアクションや キーボードショートカットを 追加するようにしましょう カスタムアクションとキーボードショートカットは 簡単に発見できるだけでなく キーボードを使ってAppを 操作する人の体験を向上させます ゲームの話に戻りましょう 新しい三角形を追加しました ここで Shit+Tabを使って ホームボタンの方に戻ります しかし そうしているうちに 別の問題が見えてきました Spaceキーで三角形を タップしても何も起こらないのに その三角形は選択可能になっているのです まず第一に 操作できないならなぜ なぜカーソルがこの要素に 向かっているのでしょうか? このAppはVoiceOverの サポート作業を既に行っていますが これはその様子です アイテムのisAccessibilityElementをtrueに設定し accessibilityLableを 付与されていることが分かります VoiceOverはユーザーに 各アイテムを読み上げる必要があるので これは 素晴らしいことです しかし フルキーボードアクセスのみの ユーザーの場合 カーソルはisAccessibilityElementでマークされた 多くのアイテムにも行きます フルキーボードアクセスに この要素をスキップするように 指示するためにはもう1行追加する必要があります accessibilityRespondsToUserInteractionを falseに設定しています これは この要素が アクセシビリティ要素ではあるものの ユーザーが対話できる要素ではないことを システムに伝えています 「フルキーボードアクセス」や 「スイッチコントロール」などの モーター技術用のカーソルは これをスキップする必要があります アクセシビリティRespondsToUserInteractionは isAccessibilityElementが すでに真である場合にのみ 意味を持つことに注意してください デフォルトでは システムは isAccessibilityElementが要素を インタラクティブにするかどうかを 正しく設定しようとします 殆どの場合 accessibilityRespondsToUserInteractionを falseに設定する必要があるのは VoiceOverには対応しているが フルキーボードアクセスや その他のモーター技術には対応していない オブジェクトがある場合だけです ここでフルキーボードアクセスを実現するための 2つ目の重要な原則があります Appをテストする際には ユーザーが操作できるアイテムにのみ カーソルが移動することを確認する必要があります Appを構築し 適切な場所にのみ フォーカスが当たるようにするためには 先ほど説明したAPIではなくcanBecomeFocusedを オーバーライドしたくなるかもしれません しかし これはフォーカスエンジン 全体のフォーカス動作を 上書きすることになり フルキーボードアクセス がオンになっていないときに Tabキーを使ってナビゲートする ユーザーに影響を与えます そのため フルキーボードアクセス のユーザーに対してのみ 動作を変更したい場合は この方法は避けた方が良いでしょう 実は これが重要なポイントになります フルキーボードアクセスを 駆動するために使用されている フォーカスシステムはiPadOS等のすべてのOSで Tabナビゲーションを駆動するのと同じものです フルキーボードアクセスを使う上で このシステムに触れる必要はないかもしれませんが もっと詳しく知りたいという方には この3つの講義をお勧めします 今年は「iPadキーボードナビゲーション」と 「SwiftUIのダイレクトフォーカスと リフレクションフォーカス」という 講義もあります そして2017年には フォーカス エンジンがどのようにtvOSを 動かしているかについての 素晴らしい講義がありました さて ホーム画面に戻って フルキーボードアクセスの すごい検索機能が使えるかどうかを 確認したいと思います では 試してみましょう OK ナンバーレベルは箱から出してすぐに使えます 8と12のレベルを検索するのは簡単です また すでにVoiceOverをサポートしているので 「Settings」ボタンも「検索」で表示されます でも そのボタンが「Settings」と 呼ばれることを知らなければ どうなるでしょうか? 「preferences」または 「prefs」と入力するかもしれません ダメですね この問題を解決するには文字列の配列を accessibilityUserInputLablesに設定します ここでは prefs preferences gear settingsなどのローカライズされた単語を このラベルに設定して 何を入力しても届くようにしています これらの文字列を追加することで 音声コントロールのユーザーにも これらの名前を声に出して Settingsボタンを押すことができるようになります もちろん VoiceOverのラベルに支障はありません これで「prefs」と入力すると 見事に動作するようになりました そして これが今日の3つ目のそして最後の原則です 画像ベースのコントロールには できるだけ多くのラベルを用意して ユーザーが「検索」して すぐにたどり着けるようにします さて この話を終える前に 少し磨きをかけてみたいと思います もう一度 ホーム画面を見てみましょう これらの項目はすべてUIボタンなので Tabは自然にそれらのアイテムに移動しています それは良いことです しかし カーソルがいつも長方形 であることに気づきましたか? もっと遊び心のあるものにするために ボタンの形に合わせてみましょう ボタンの周りにきれいなカーソルの 形を表示するには accessibilityPathを使います そう VoiceOverで使ったのと同じ accessibilityPathです 静的なビューではaccessibilityPathを UIBezierPathで形状 そのものに設定することができます ここでaccessibilityPathを 画面座標で設定していることに注目してください スクロールビューの場合はaccessibilityPathを オーバーライドすることでスクロールしても 常に画面座標に相対するように 設定することができます それでは このちょっとした改良が どれ位楽しいものか見てみましょう Tabで移動すると丸 三角 四角が 表示されています VoiceOVerでも同じように表示されます それでは キーボード用App 特にフルキーボードアクセス用のAppを開発する際に 念頭に置くべき重要な点を確認しましょう まず カスタムアクションと キーボードショートカットを使って Appを効率的に操作できるようにします 次に ユーザーが実際に操作できないアイテムに カーソルが行かないようにします 最後に ユーザーがフルキーボード アクセスの検索機能を 最大限に活用できるように 特に画像ベースのコントロールには ユーザー入力ラベルを追加してください それで完成です 本日は Appleのすべての製品における モーターアクセシビリティの重要性を ご理解いただけたと思います 私たちのデバイスを 操作する方法は数多くありますが キーボードはユーザーにとって 強力なツールとなっています この講義で得た情報をもとに あなたのAppが フルキーボードアクセスユーザーやすべての人に 素晴らしい体験を提供することが できるようになるでしょう ありがとうございました どうぞ 素晴らしいWWDC2021を ♪
-
-
7:06 - Accessibility custom actions
// Accessibility custom actions let addAction = UIAccessibilityCustomAction( name: gameLocString("add"), image: UIImage(systemName: "plus.square")) { _ in self.addCard() return true } let pinAction = UIAccessibilityCustomAction( name: gameLocString("pin"), image: UIImage(systemName: "pin.fill")) { _ in self.pinCard() return true } cardView.accessibilityCustomActions = [addAction, pinAction]
-
8:39 - Keyboard shortcuts: buildMenu
// Keyboard shortcuts // In AppDelegate.swift override func buildMenu(with builder: UIMenuBuilder) { super.buildMenu(with: builder) guard builder.system == .main else { return } let pinCommand = UIKeyCommand(title: gameLocString("pin"), image: UIImage(systemName: "pin.fill"), action:#selector(GameViewController.pinFocusedCard), input: "P", discoverabilityTitle:gameLocString("pin.card")) let addCommand = UIKeyCommand(title: gameLocString("add"), image: UIImage(systemName: "plus.square"), action: #selector(GameViewController.addFocusedCard), input: "A", discoverabilityTitle: gameLocString("add.card")) let identifier = UIMenu.Identifier("gameplay_menu") let menu = UIMenu.init(title: gameLocString("gameplay"), image: UIImage(systemName "rectangle.grid.3x2"), identifier: identifier, children: [addCommand, pinCommand]); builder.insertSibling(menu, afterMenu: .view) }
-
9:22 - Keyboard shortcuts: canPerformAction
// Keyboard shortcuts // In GameViewController.swift override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { if action == #selector(addFocusedCard) || action == #selector(pinFocusedCard) { return self.focusedCard != .none } return super.canPerformAction(action, withSender: sender) }
-
10:35 - Accessibility elements
itemView.isAccessibilityElement = true itemView.accessibilityLabel = gameLocString(for: item)
-
11:01 - Responding to user interaction
itemView.accessibilityRespondsToUserInteraction = false
-
13:41 - Supporting accessible input
self.accessibilityUserInputLabels = [ gameLocString("settings"), gameLocString("prefs"), gameLocString("preferences"), gameLocString("gear")];
-
14:52 - Accessibility path
// Accessibility path let rect = circleLevelButton.convert(levelButton.bounds, to: nil) circleLevelButton.accessibilityPath = UIBezierPath(ovalIn: rect) // If your button is in a scroll view, it’s generally better to // override accessibilityPath and/or accessibilityFrame extension CircleButton { open override var accessibilityPath: UIBezierPath? { get { let rect = self.convert(self.bounds, to: nil) return UIBezierPath(ovalIn: rect) } set { // no-op } } }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。