ユーザー補助を必要とする人々がアプリを適切に使用できるようにするには、主要なユーザー補助の要件に対応するようにアプリを設計します。
タップ ターゲットの最小サイズを検討する
クリック、タップなど、ユーザーが操作できる画面上の要素はすべて、確実に操作できるよう十分な大きさにする必要があります。これらの要素のサイズを設定する場合は、マテリアル デザインのユーザー補助のガイドラインに沿って、最小サイズを 48 dp に設定してください。
マテリアル コンポーネント(Checkbox
、RadioButton
、Switch
、Slider
、Surface
など)は、この最小サイズを内部で設定しますが、これはコンポーネントがユーザー アクションを受け取れる場合に限ります。たとえば、Checkbox
の onCheckedChange
パラメータが null 以外の値に設定されている場合、チェックボックスには、幅と高さが 48 dp 以上のパディングが含まれます。
@Composable private fun CheckableCheckbox() { Checkbox(checked = true, onCheckedChange = {}) }
onCheckedChange
パラメータが null に設定されている場合、コンポーネントは直接操作できないため、パディングは含まれません。
@Composable private fun NonClickableCheckbox() { Checkbox(checked = true, onCheckedChange = null) }
Switch
、RadioButton
、Checkbox
などの選択コントロールを実装する場合、通常は、クリック可能な動作を親コンテナにリフトし、コンポーザブルのクリック コールバックを null
に設定し、親コンポーザブルに toggleable
または selectable
修飾子を追加します。
@Composable private fun CheckableRow() { MaterialTheme { var checked by remember { mutableStateOf(false) } Row( Modifier .toggleable( value = checked, role = Role.Checkbox, onValueChange = { checked = !checked } ) .padding(16.dp) .fillMaxWidth() ) { Text("Option", Modifier.weight(1f)) Checkbox(checked = checked, onCheckedChange = null) } } }
クリック可能なコンポーザブルのサイズがタップ ターゲットの最小サイズより小さい場合、Compose はタップ ターゲットのサイズを大きくします。そのためには、コンポーザブルの境界外にタップ ターゲットのサイズを拡大します。
次のサンプルには、非常に小さいクリック可能な Box
が含まれています。タップ ターゲット領域は Box
の境界を越えて自動的に拡張されるため、Box
の横をタップしてもクリック イベントがトリガーされます。
@Composable private fun SmallBox() { var clicked by remember { mutableStateOf(false) } Box( Modifier .size(100.dp) .background(if (clicked) Color.DarkGray else Color.LightGray) ) { Box( Modifier .align(Alignment.Center) .clickable { clicked = !clicked } .background(Color.Black) .size(1.dp) ) } }
異なるコンポーザブルのタッチ領域が重複しないように、コンポーザブルには十分な大きさの最小サイズを使用します。この例では、sizeIn
修飾子を使用して内部ボックスの最小サイズを設定します。
@Composable private fun LargeBox() { var clicked by remember { mutableStateOf(false) } Box( Modifier .size(100.dp) .background(if (clicked) Color.DarkGray else Color.LightGray) ) { Box( Modifier .align(Alignment.Center) .clickable { clicked = !clicked } .background(Color.Black) .sizeIn(minWidth = 48.dp, minHeight = 48.dp) ) } }
クリックラベルを追加する
クリックラベルを使用して、コンポーザブルのクリック動作に意味論的意味を追加できます。クリックラベルは、ユーザーがコンポーザブルを操作したときにどうなるかを記述します。ユーザー補助サービスでは、特定のニーズのあるユーザーにアプリを説明するためにクリックラベルを使用します。
clickable
修飾子にパラメータを渡してクリックラベルを設定します。
@Composable private fun ArticleListItem(openArticle: () -> Unit) { Row( Modifier.clickable( // R.string.action_read_article = "read article" onClickLabel = stringResource(R.string.action_read_article), onClick = openArticle ) ) { // .. } }
クリック可能な修飾子にアクセスできない場合は、semantics 修飾子でクリックラベルを設定します。
@Composable private fun LowLevelClickLabel(openArticle: () -> Boolean) { // R.string.action_read_article = "read article" val readArticleLabel = stringResource(R.string.action_read_article) Canvas( Modifier.semantics { onClick(label = readArticleLabel, action = openArticle) } ) { // .. } }
視覚要素を説明する
Image
または Icon
のコンポーザブルを定義しても、Android フレームワークがアプリの表示内容を自動的に認識する方法はありません。視覚要素のテキストによる説明を渡す必要があります。
ユーザーが現在のページを友だちと共有できる画面があるとします。この画面には、クリック可能な共有アイコンがあります。
Android フレームワークは、アイコンだけでは視覚障がいのあるユーザーにアイコンを説明することができません。Android フレームワークには、アイコンの説明テキストを追加する必要があります。
contentDescription
パラメータは視覚要素を記述します。ユーザーに表示されるため、ローカライズされた文字列を使用します。
@Composable private fun ShareButton(onClick: () -> Unit) { IconButton(onClick = onClick) { Icon( imageVector = Icons.Filled.Share, contentDescription = stringResource(R.string.label_share) ) } }
一部の視覚要素は純粋に装飾的なものであり、ユーザーに伝えたくない場合があります。contentDescription
パラメータを null
に設定すると、この要素にアクションや状態が関連付けられていないことを Android フレームワークに示すことになります。
@Composable private fun PostImage(post: Post, modifier: Modifier = Modifier) { val image = post.imageThumb ?: painterResource(R.drawable.placeholder_1_1) Image( painter = image, // Specify that this image has no semantic meaning contentDescription = null, modifier = modifier .size(40.dp, 40.dp) .clip(MaterialTheme.shapes.small) ) }
特定の視覚要素に contentDescription
が必要かどうかは自由に決定できます。その要素が、ユーザーがタスクを行うために必要な情報を伝えるものであるかどうかを自問してください。そうでない場合は、説明を省略することをおすすめします。
要素を結合する
TalkBack やスイッチ アクセスなどのユーザー補助サービスでは、ユーザーは画面上の要素間でフォーカスを移動できます。適切な粒度で要素がフォーカスされることが重要です。画面内の低レベルのコンポーザブルがそれぞれ独立してフォーカスされている場合、ユーザーは画面上を移動するために多くの操作が必要になります。要素の結合が強すぎると、どの要素が互いに属しているか分からなくなる可能性があります
コンポーザブルに clickable
修飾子を適用すると、Compose はコンポーザブルに含まれるすべての要素を自動的に結合します。これは ListItem
にも適用されます。リストアイテム内の要素はマージされ、ユーザー補助サービスでは 1 つの要素として認識されます。
論理グループを形成するコンポーザブルのセットを持つことはできますが、そのグループはクリック可能ではなく、リストアイテムの一部でもありません。ユーザー補助サービスでは、これらを 1 つの要素として表示する必要があります。たとえば、ユーザーのアバター、名前、追加情報を表示するコンポーザブルを考えてみます。
semantics
修飾子で mergeDescendants
パラメータを使用すると、Compose でこれらの要素を結合できるようになります。これにより、ユーザー補助サービスは結合された要素のみを選択し、子孫のすべてのセマンティクス プロパティが結合されます。
@Composable private fun PostMetadata(metadata: Metadata) { // Merge elements below for accessibility purposes Row(modifier = Modifier.semantics(mergeDescendants = true) {}) { Image( imageVector = Icons.Filled.AccountCircle, contentDescription = null // decorative ) Column { Text(metadata.author.name) Text("${metadata.date} • ${metadata.readTimeMinutes} min read") } } }
ユーザー補助サービスはコンテナ全体を一度に処理して、コンテンツをマージするようになりました。
カスタム アクションを追加する
以下のリストアイテムをご覧ください。
TalkBack などのスクリーン リーダーを使用して、画面に表示されている内容を読み上げる場合は、まずアイテム全体を選択してから、ブックマーク アイコンを選択します。
長いリストは、繰り返しが多い場合があります。推奨されるアプローチは、ユーザーがアイテムをブックマークできるカスタム アクションを定義することです。また、ブックマーク アイコン自体の動作を明示的に削除して、ユーザー補助サービスで選択されないようにする必要があります。そのためには clearAndSetSemantics
修飾子を使用します。
@Composable private fun PostCardSimple( /* ... */ isFavorite: Boolean, onToggleFavorite: () -> Boolean ) { val actionLabel = stringResource( if (isFavorite) R.string.unfavorite else R.string.favorite ) Row( modifier = Modifier .clickable(onClick = { /* ... */ }) .semantics { // Set any explicit semantic properties customActions = listOf( CustomAccessibilityAction(actionLabel, onToggleFavorite) ) } ) { /* ... */ BookmarkButton( isBookmarked = isFavorite, onClick = onToggleFavorite, // Clear any semantics properties set on this node modifier = Modifier.clearAndSetSemantics { } ) } }
要素の状態を説明する
コンポーザブルは、Android フレームワークがコンポーザブルの状態を読み出すために使用するセマンティクスに stateDescription
を定義できます。たとえば、切り替え可能なコンポーザブルは、「オン」または「オフ」の状態にすることができます。Compose が使用するデフォルトの状態説明ラベルをオーバーライドする必要がある場合があります。これを行うには、コンポーザブルを切り替え可能として定義する前に、状態説明のラベルを明示的に指定します。
@Composable private fun TopicItem(itemTitle: String, selected: Boolean, onToggle: () -> Unit) { val stateSubscribed = stringResource(R.string.subscribed) val stateNotSubscribed = stringResource(R.string.not_subscribed) Row( modifier = Modifier .semantics { // Set any explicit semantic properties stateDescription = if (selected) stateSubscribed else stateNotSubscribed } .toggleable( value = selected, onValueChange = { onToggle() } ) ) { /* ... */ } }
見出しを定義する
アプリは、スクロール可能なコンテナの 1 つの画面に多数のコンテンツを表示することがあります。たとえば、1 つの画面にユーザーが読んでいる記事のすべての内容を表示する場合などです。
ユーザー補助機能を利用しているユーザーは、そのような画面をナビゲートしにくいことを必要としている。ナビゲーションを支援するために、どの要素が見出しであるかを示します。上記の例では、各サブセクションのタイトルをユーザー補助機能の見出しとして定義できます。TalkBack などの一部のユーザー補助サービスでは、ユーザーが見出しから見出しに直接移動できます。
Compose で、コンポーザブルが見出しであることを示すには、その semantics
プロパティを定義します。
@Composable private fun Subsection(text: String) { Text( text = text, style = MaterialTheme.typography.headlineSmall, modifier = Modifier.semantics { heading() } ) }
カスタム コンポーザブルを処理する
アプリの特定のマテリアル コンポーネントをカスタム バージョンに置き換える場合は、ユーザー補助に関する考慮事項を念頭に置く必要があります。
マテリアルの Checkbox
を独自の実装に置き換えるとします。このコンポーネントのユーザー補助プロパティを処理する triStateToggleable
修飾子を追加し忘れても構いません。
経験上、マテリアル ライブラリのコンポーネントの実装を確認し、任意のユーザー補助動作を再現します。さらに、UI レベルの修飾子ではなく、Foundation 修飾子を多用します。これらの修飾子には、すぐに利用できるユーザー補助機能の考慮事項が含まれています。
複数のユーザー補助サービスを使用してカスタム コンポーネントの実装をテストし、その動作を検証します。
参考情報
- ユーザー補助: すべての Android アプリ開発に共通する基本的なコンセプトと手法
- 誰にとっても使いやすいアプリを作成する: アプリのユーザー補助機能を向上させるための重要なステップ
- アプリのユーザー補助機能を改善するための原則: アプリのユーザー補助機能を強化する際に留意すべき主な原則
- ユーザー補助機能のテスト: Android のユーザー補助機能に関するテストの原則とツール