Jetpack Compose から始める、アクセシビリティ

こんにちは。KyashのMobileチームでAndroidアプリを開発している牛窪です。
皆さんは個人開発・会社でのプロダクトにかかわらずJetpack Compose導入していますでしょうか。勉強会やBlogはじめアウトプットしている方が増えているように感じています。

Kyash AndroidチームではライブラリがBeta段階から新規画面にJetpack Composeを採用し始めています。この記事ではJetpack Composeのアクセシビリティにフォーカスしてどのような取り組みを始めているか簡単な実装例を交えながらお話しします。

なぜアクセシビリティに取り組み始めたか

二つ理由があります。

一つ目はユーザーからの問い合わせです。数カ月前Jetpack Composeの導入をKyashアプリで進めている中、視覚障がいの方から使いやすくしていただきたい旨の問い合わせをいただきました*1。その方はiOSユーザーのため直接関係はありませんが、Kyashとしてアクセシビリティ対応に自分が取り組みたいと思ったからです。

二つ目はGoogleが近年アクセシビリティに特に力を入れていると感じたからです。アクセシビリティに関して公式ドキュメントの充実や・YouTubeで動画が多く公開されるようになってきています。また、Jetpack ComposeにおいてもAlpha段階からアクセシビリティについて実装されていたためとても興味を持ちました。

そもそもアクセシビリティとは何か

Androidアプリでのアクセシビリティとは「操作のしやすさ」といってよいでしょう。たびたび高齢者・障がい者のためのものと解釈されがちですがそうではなく、あらゆる人がどのような環境でも等しく操作しやすくするために必要です。

例えば、眼鏡をかけている人が外して操作をする場合は視力が低下していたり、外出時に日差しが強く画面が反射している場合は色覚情報が低下することにより操作がしづらくなります*2

このように誰でもアクセシビリティを必要とする場面が出てきます。アクセシビリティと一口に言っても対応するべき内容はさまざまではありますが、できる範囲から取り組むことでユーザーにとって大きな助けになるでしょう。

Composeでアクセシビリティを考慮した実装

それではJetpack Composeでアクセシビリティ対応としてできることを一部紹介していきます。Jetpack Composeのバージョンは1.0.2です。

一例として規約同意画面を作ってみました。この時点ではアクセシビリティ考慮は全くしていません。

gist.github.com

デプロイしてみるとこのような画面になります。

この画面は、ユーザーが利用規約を読み同意する チェックボックスにチェックをすると下の 次へ進む ボタンが活性し、次の画面へ進むことができる画面です。

それではアクセシビリティ対応で実装がどう変わるのかみていきましょう!

TalkBack対応

Android端末ではTalkBackというGoogle製のスクリーンリーダーが入っています*3。 TalkBackを利用すると画面を見ずにデバイスを操作できます。 まずは、端末の設定のアクセシビリティからTalkBackを有効にしてください*4

アクセシビリティ TalkBack

TalkBackでは操作方法が通常と異なります。またカスタムができるようにもなっています。 標準でのTalkBackの操作方法はAndroidのユーザー補助ヘルプをご覧ください。

それでは実装した利用規約画面を操作して読み上げさせてみます。結果はこちらです。

ツールバーの戻るボタン部分: ボタン、ダブルタップすると有効になります
チェックボックス: チェックボックス、toggleするにはダブルタップします
下部ボタン部分: 次へ進むボタン、無効
他テキスト部分: そのまま読み上げ

これを受けて大きく分けて以下の三つが改善できそうです。

  • contentDescriptionの設定
  • LiveRegion
  • Grouping

それでは順番に見ていきましょう。

contentDescriptionの設定

IconはcontentDescriptionがnullとして設定されているためそれをタップしてもそれが何かわかりません。何を表すアイコンなのか示したい場合は適切なcontentDescriptionを設定する必要があります。今回は 戻る とするとよりわかりやすいですね。

ButtonはcontentDescriptionが設定されてない場合、子のTextの内容を読み上げますがModifier.semantics を使いcontentDescriptionを設定することで、その内容を読み上げることができるためボタンの有効・無効に応じて読み上げ内容を変えることでより親切なものとなりそうです。こちらは後述のLiveRegionの際に一緒に説明します。

contentDescriptionはわかりやすくそれ固有の説明であれば大丈夫ですが、その要素の種類 (例えばボタンやツールバー) を文言に含めないようにします。なぜならTalkBackで要素の種類を読み上げてくれるからです。 また、装飾効果のみのIconやImageでは読み上げさせる必要がないためcontentDescriptionはあえてnullを設定してください。

LiveRegionの設定

同意する チェックボックスにチェックをすると下の 次へ進む ボタンが活性し、次の画面へ進むことができる画面

これは目で確認できる場合はチェックボックスをつけることでボタンが有効になったことがすぐわかりますが、そうでない場合はボタンが有効になったことに気づきにくい問題があります。

このような問題にはLiveRegionが有効です。LiveRegionとはフォーカスされていないコンテンツの変更を認識できるようにすることです。 Jetpack ComposeのLiveRegionでは子のcontentDescriptionならびにtextの内容の変更を知らせてくれます。

1つの解決策としてボタンのcontentDescriptionを有効・無効時にそれぞれ設定しておけば、LiveRegionを設定しておくことでボタンの有効・無効時に読み上げをすることができます。 contentDescriptionもLiveRegionも以下のsnippetのようにModifier.semantics から設定することができます。

gist.github.com

この実装によりチェックボックスの状態に応じて下部ボタンの読み上げ内容が変わりました。

Jetpack ComposeのLiveRegionは二種類のModeがあり、LiveRegionMode.AssertiveLiveRegionMode.Politeがあります。 前者は変更された瞬間に現在フォーカスしているものの読み上げを遮って新たな変更を読み上げます。 後者は現在フォーカスしている読み上げが終わった後、新たな変更を読み上げます。状況に応じて使い分けるとよさそうです。

ただし、Composableが頻繁に数カ所で更新されるような画面の場合、LiveRegionを設定することで逆にユーザーが混乱してしまうことがありえます。必要な箇所のみ設定することをお勧めします。

Grouping

利用規約画面の第1条・第2条は見出しということに気づきます。TalkBackでは読み上げのニーズに応じて、見出しのみフォーカスを当てて読み上げることができる機能があります。 実際に目で確認する場合も見出しからチェックして興味のある見出しの詳細から読み始めるという方も多いのではないでしょうか。

このようなGroupingのニーズに対応するためにModifier.semanticsではheading()をサポートしています。この記述だけで見出しとして認識されます。 Modifier.semanticsの中にはこのように便利なものが最初から定義されているのでチェックしてみてください*5

また、今回の画面では関係はないですが、Modifier.semantics(mergeDescendants = true)もよく使われます。 trueにすることによって子の要素それぞれにフォーカスして読み上げすることなくまとめてフォーカスがあたり子の内容が読み上げられるため、ユーザーの操作回数を減らすことができます。意味のまとまりが良いcomposableに対して設定するとわかりやすいですね。

タッチ領域の対応

Androidアクセシビリティ公式ドキュメント*6では少なくとも48dp x 48dpのフォーカス可能領域を設定することが推奨されています。

そのためJetpack Composeでは大きく分けて二種類の解決法があります。

  • Modifier.defaultMinSizeModifier.sizeを使い、フォーカスするcomposableが48dp以上であることを保証する
  • タッチ可能領域のcomposableを定義し、そこにタッチイベントなどを委譲する

前者は対象のcomposableに対して48dp以上を保証することでそれを満たすというものです。ただし、TextやButtonのような文言によってsizeが可変となる場合はModifier.defaultMinSizeModifier.fillMaxWidthなど使うことをお勧めします。 後者はBoxなど使い、元のcomposableのサイズは変えられないがタッチ領域を増やすやり方などが該当します。AndroidxmlではViewやFrameLayoutなど重ねた方はいらっしゃるのではないでしょうか。

今回の利用規約画面ではTextに該当するものは前者のやり方で解決しそうで、下部ボタンは後者のやり方で解決しそうです。

ではチェックボックスはどうでしょうか。チェックボックスのサイズをデザイン観点で変えられないとしたらどうするのがよいでしょう。 後者のやり方で解決できますが、チェックボックス同意するのTextを一つの列とみなしてタッチできるようにする方が親切そうです。そこで定義されているRowに対してModifierを設定します。

gist.github.com

元のmodifier = Modifier.fillMaxWidth()と比べると.toggleable()が追加されていることがわかります。これは対象のcomposableをtoggleできるものとして扱うために定義されているModifierです。 toggleできるものとはCheckBoxSwitchなどがこれに該当します。アクセシビリティ観点ではこれを使うことでツール群がこれはtoggleできるものと認識させることができます。 ただし、RowのModifierにてこれらを定義したため大元のCheckboxonCheckedChangeはnullにする必要があります。

このようにJetpack Composeではタッチ領域をサポートできるAPIが用意されているのでぜひ気を配ってみてください。

フォントサイズ

Android端末の設定ではシステム全体のフォントサイズを変更する機能があり、ユーザーはこの機能をよく使います。このフォントサイズの変更を考慮することで想定外の画面崩れを予防できます。
実際に端末で変えて確かめてみてもいいですが、PreviewConfigurationの機能で簡単に試すことができるので紹介します。

AndroidStudioのPreviewのcomposable関数にて歯車のアイコンをクリックするとこのようなウィンドウが表示されます。そこでfontScaleを変えたり、同時にwidthDpを変えたりすることで画面崩れがないかしっかりと確認できます。 デプロイまでして確認するとどうしても時間がかかってしまうのと、PreviewConfigurationではこの他にもさまざまな条件を追加できるため大変使いやすいです。ぜひ試してみてください。

コントラスト

前景色と背景色はそれぞれコントラスト比が十分になるよう指定する必要があります。 W3Cの推奨設定では

  • 小さい文字サイズ(標準 18 ポイント、太字 14 ポイント未満)では 4.5:1 以上
  • 大きい文字サイズ(標準 18 ポイント、太字 14 ポイント以上)では 3.0:1 以上

とする必要があります。

デザイナーがコントラストに対して気を配っている場合は考慮する必要はないかもしれませんが、Androidエンジニアが確認する場合はユーザー補助検証ツールを使うことをお勧めします。 ユーザー補助検証ツールは端末設定のアクセシビリティ内もしくはAndroidユーザー補助設定ツール内にあります。この設定をONにすることで現在の画面をスキャンしアプリのアクセシビリティを改善するための提案をしてくれます。 下部右図はアクセシビリティ実装する前の画面にてスキャンを行った結果です。オレンジで囲まれた部分をタップすることで提案内容が表示されます。

ユーザー補助検証ツール スキャン結果

コントラスト含め前述したタッチ領域などさまざまな内容に対して改善提案をしてもらえるのでぜひ利用してアクセシビリティに考慮した実装をしてみてはいかがでしょうか。

最終的な結果

前述したアクセシビリティ実装をすべて行った最終的なコードを記しておきます。

gist.github.com

またこの画面を先ほどのユーザー補助検証ツールでスキャンしてみましょう。

提案なしになりましたね!この状態をKyashアプリの各画面でも目指していきたいと思います。

アクセシビリティ対応をしてみて

Jetpack Compose環境下のアクセシビリティ実装を一部紹介させていただきました。アクセシビリティ実装は画面ごとに考慮すべきことが多種多様であると感じています。 いきなり全て対応することは難しいですが、プロダクトごとどういうユーザーに対して何をサポートするかガイドラインを策定したり、できることからはじめることでどのようなユーザー・環境下でも操作しやすいアプリにしていきたいですね。

実際に対応してみると、UIの動作確認に気を使うようになりUI面の不具合や考慮漏れが減っているようように感じられ、その点メリットだと考えています。 みなさんもぜひアクセシビリティ実装をしてみてはいかがでしょうか。

最後にKyashではAndroidエンジニアを募集しています。
最新の技術やバージョン更新に気を配りつつプロダクトへの導入を積極的に行っています。 流行りのJetpack Composeだけでなく、一見マイナーですがとても大事なアクセシビリティ対応であったり、当人のやりたいことを実現できる環境だと感じています。
ぜひ興味がありましたら下記のリンクからカジュアルにお話ししましょう!

open.talentio.com

docs.google.com

*1:詳細は「お客さまの声」を起点としたサービスの継続的改善にて書いています。

*2:状況的障がい(Situational Disability)と言ったりもします。

*3:メーカー・OSによっては入っていないこともありますがAndroidユーザー補助設定ツールをインストールすれば大丈夫です。

*4:画面自体はメーカー・OSによって微妙に異なります。

*5:https://developer.android.com/reference/kotlin/androidx/compose/ui/semantics/package-summary?hl=ja

*6:https://developer.android.com/guide/topics/ui/accessibility/apps?hl=ja#large-controls