アプリのユーザー補助機能の改善に関する原則

ユーザー補助機能を必要とするユーザーをサポートするため、Android フレームワークでは、アプリのコンテンツをユーザーに提示したり、ユーザーの代わりにアプリを操作したりできるユーザー補助サービスを作成できます。

Android では、次のようなシステムのユーザー補助サービスを提供しています。

ユーザー補助機能を必要とするユーザーがアプリを快適に利用できるように、このページで説明されているおすすめの方法に沿ったアプリを作成する必要があります。おすすめの方法は、アプリのユーザー補助機能を強化するで説明したガイドラインに基づいています。

以降のセクションで説明するおすすめの方法を実践することで、アプリのユーザー補助機能をさらに強化できます。

要素にラベルを付ける
アプリ内で操作対象になる有用な各 UI 要素について、その内容と目的をユーザーが理解できるようにする必要があります。
ユーザー補助アクションを追加
ユーザー補助アクションを追加することで、ユーザー補助サービスのユーザーがアプリ内で重要なユーザーフローを完了できるようにします。
組み込みのユーザー補助機能を使用する
Compose には、デフォルトで多くのユーザー補助動作が用意されています。事前定義されたユーザー補助動作を利用することで、追加の作業をほとんど、またはまったく行わずにコンポーネントをユーザー補助に対応させることができます。Compose には、デフォルトの機能では対応していない、より具体的なユーザー補助要件をサポートする方法も用意されています。
色以外の手がかりも取り入れる
ユーザーが UI の要素の種類を明確に区別できるようにする必要があります。そのためには、色だけでなく、パターンや位置によって、こうした区別を表します。
メディア コンテンツのユーザー補助機能を強化する
アプリの動画や音声コンテンツに説明を追加して、コンテンツを消費するユーザーが視覚的な手がかりや音声の手がかりだけに頼らないでもすむようにします。

要素にラベルを付ける

アプリ内の操作対象の UI 要素ごとに、有用でわかりやすいラベルをユーザーに提供することが重要です。各ラベルで、その特定の要素のセマンティクス(要素の意味と目的)を説明する必要があります。TalkBack などのスクリーン リーダーは、こうしたサービスに頼るユーザーにそのラベルを読み上げることができます。

ほとんどの場合、Compose API と Material には デフォルトのユーザー補助サポートが用意されています。ただし、UI 要素のセマンティック プロパティを手動で指定する必要がある場合は、semantics 修飾子と contentDescription プロパティを使用します。セマンティクスの詳細については、 セマンティクスをご覧ください。

以降のセクションでは、その他のラベル付け手法について説明します。

編集可能な要素

テキスト フィールドのように編集可能な要素にラベルを付ける場合、その要素そのものへの有効な入力テキスト例を、スクリーン リーダーが利用できるようにするだけでなく、表示しておくと便利です。このような場合は、プレースホルダ テキスト(ヒントテキストとも呼ばれます)を使用できます。

次の例では、TextField にヒントテキストを提供する placeholder パラメータがあります。

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

また、テキスト フィールドには、ユーザーが入力する必要がある内容を説明する対応する説明ラベルが用意されていることも一般的です。

次の例では、TextField にユーザー補助の説明を提供する label パラメータがあります。

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

テキストとユーザー入力の詳細については、テキスト フィールドを構成するをご覧ください。

コレクション内の要素

コレクションの要素にラベルを指定する場合、各ラベルは固有である必要があります。 そうすることで、システムのユーザー補助サービスがラベルを読み上げる際、画面上の要素を 1 つずつ正確に参照できます。こうした対応関係により、ユーザーは UI の確認が一巡したことや、以前に確認した要素にまたフォーカスを移動したことを判断できます。

たとえば、LazyColumn または LazyRow がある場合は、次のスニペットに示すように、semantics 修飾子を使用して、各アイテムに一意の collectionItemInfo を割り当てます。

MilkyWayList(
    modifier = Modifier
        .semantics {
            collectionInfo = CollectionInfo(
                rowCount = milkyWay.count(),
                columnCount = 1
            )
        }
) {
    milkyWay.forEachIndexed { index, text ->
        Text(
            text = text,
            modifier = Modifier.semantics {
                collectionItemInfo =
                    CollectionItemInfo(index, 0, 0, 0)
            }
        )
    }
}

リストとグリッドのセマンティクス プロパティの詳細については、 リストとアイテムの情報をご覧ください。

関連コンテンツのグループ

曲の詳細やメッセージの属性など、自然なグループを構成する複数の UI 要素をアプリで表示する場合、親コンテナ(ColumnRowBox など)内にそれらの要素を配置します。親コンテナの semantics 修飾子を使用して、mergeDescendantstrue に設定します。

そうすることで、ユーザー補助サービスが内部の要素のコンテンツの説明を、続けて一度に読み上げて紹介することができます。関連要素をこうして統合すると、補助サービスのユーザーが画面上にある情報を効率よく発見できるようになります。

次のスニペットでは、Row コンポーザブルが親コンテナとして機能します。 Row 内には、ブログ投稿のメタデータ(著者のアバター、著者の名前、推定読了時間)を表示する関連要素があります。mergeDescendantstrue に設定すると、これらの内部要素がグループ化されるため、ユーザー補助サービスはこれらを 1 つの単位として扱うことができます。

@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")
        }
    }
}

前の例のように関連要素をグループ化する場合は、親コンテナのみをインタラクティブにします。内部の子要素に clickable 修飾子や focusable 修飾子を追加しないでください。代わりに、親の Row または Column に修飾子を適用します。

ユーザー補助サービスが内部要素の説明を一度に読み上げるので、各説明は要素の意味を伝える一方で、できる限り短くすることが重要です。

注: 一般に、グループのコンテンツの説明を作成する場合は、子要素のテキストを集約しないようにしてください。そうすると、グループの説明が脆弱になり、子要素のテキストが変更されたときに、グループの説明が表示テキストと一致しなくなる可能性があります。

リストまたはグリッドのコンテキストでは、スクリーン リーダーがリストまたはグリッド要素の子テキストノードのテキストを統合する場合があります。このお知らせを変更しないことをおすすめします。

セマンティクスの統合の詳細については、統合とクリアをご覧ください。

テキスト内の見出し

一部のアプリでは画面上に表示するテキスト グループの概要を、見出しを使って示すことがあります。 特定の要素が見出しを表す場合、semantics 修飾子の heading プロパティを設定することでそうした意図をユーザー補助サービスに示すことができます。

@Composable
private fun Subsection(text: String) {
    Text(
        text = text,
        style = MaterialTheme.typography.headlineSmall,
        modifier = Modifier.semantics { heading() }
    )
}

補助サービスのユーザーは、段落間や単語間ではなく、見出し間を移動するように選択できます。このように柔軟性が増したことで、テキスト ナビゲーションの利便性が向上します。

heading セマンティクス プロパティの詳細については、見出しをご覧ください。

ユーザー補助ペインのタイトル

Android 9(API レベル 28)以上では、画面のペインにユーザー補助に利用できるタイトルを提供できます。 ユーザー補助機能にとってペインは、ウィンドウ内で視覚上区分けされた部分です。

ペインにおけるウィンドウのような動作をユーザー補助サービスが理解するには、アプリのペインにわかりやすいタイトルを付ける必要があります。それにより、ユーザー補助サービスでは、ペインの外観やコンテンツが変更されたときに、詳細な情報をユーザーに提供できます。

ShareSheet(
    message = "Choose how to share this photo",
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.TopCenter)
        .semantics { paneTitle = "New bottom sheet" }
)

paneTitle セマンティクス プロパティの詳細については、 ウィンドウのようなコンポーネントをご覧ください。

装飾的要素

UI 内のある要素が視覚的な間隔をあけるため、または見た目のためにのみ存在する場合、その要素に適切なプロパティを設定して、ユーザー補助サービスが無視できるようにします。

Image コンポーザブルまたは Icon コンポーザブルの場合は、contentDescription = null を設定します。コンテキストや機能を提供しない、純粋に装飾的な要素の場合は、hideFromAccessibility を使用できます。このセマンティクス プロパティは、アイテムを無視するようにユーザー補助サービスに指示します。

インタラクティブなコンポーザブルに、装飾的な非インタラクティブな子要素が含まれている場合は、clearAndSetSemantics を使用して、ユーザー補助サービスがそれらをトラバースしないようにします。clearAndSetSemantics は、要素とその子要素のデフォルトのセマンティクスを完全に消去します。これにより、新しい統合されたユーザー補助要素を定義できます。通常、このアプローチは複雑なカスタム コンポーネントに使用します。

次の例では、IconText はカスタム切り替え内の装飾的な子要素です。ユーザー補助サービスがこれらの子要素を個別にトラバースしないようにするには、親の RowclearAndSetSemantics を使用してセマンティクスをクリアします。これにより、ユーザー補助サービスは Row 全体をトラバース可能な切り替えとして扱います。

// Developer might intend this to be a toggleable.
// Using `clearAndSetSemantics`, on the Row, a clickable modifier is applied,
// a custom description is set, and a Role is applied.

@Composable
fun FavoriteToggle() {
    val checked = remember { mutableStateOf(true) }
    Row(
        modifier = Modifier
            .toggleable(
                value = checked.value,
                onValueChange = { checked.value = it }
            )
            .clearAndSetSemantics {
                stateDescription = if (checked.value) "Favorited" else "Not favorited"
                toggleableState = ToggleableState(checked.value)
                role = Role.Switch
            },
    ) {
        Icon(
            imageVector = Icons.Default.Favorite,
            contentDescription = null // not needed here

        )
        Text("Favorite?")
    }
}

セマンティクスのクリアの詳細については、 セマンティクスをクリアして設定するをご覧ください。

ユーザー補助アクションを追加

ユーザー補助サービスのユーザーがアプリ内のすべてのユーザーフローを完了できるようにすることが重要です。

カスタム コンポーザブルの操作によって、アプリの状態がわかりにくい方法で変更される場合は、Modifier.clickable または Modifier.combinedClickableonClickLabelonLongClickLabel などのパラメータを使用して、標準のタップ操作にわかりやすいラベルを付けます。

標準のタップにマッピングできない複雑な操作には、customActions を使用します。

たとえば、アプリでユーザーがアイテムを別の場所にドラッグしたり、リスト内のアイテムをスワイプしたりできる場合は、アクションをユーザー補助サービスに公開することで、これらのユーザーフローを完了する別の方法を提供できます。これにより、 TalkBack、Voice Access、スイッチ アクセスのユーザーは、 ジェスチャーでのみ使用できるアクションを実行できます。

Compose では、CustomAccessibilityAction を使用して、semantics 修飾子の customActions プロパティでカスタムのユーザー補助アクションを定義できます。

たとえば、アプリでユーザーがアイテムをスワイプして閉じるようにする場合は、カスタムのユーザー補助アクションを使用して機能を公開できます。

SwipeToDismissBox(
    modifier = Modifier.semantics {
        // Represents the swipe to dismiss for accessibility
        customActions = listOf(
            CustomAccessibilityAction(
                label = "Remove article from list",
                action = {
                    removeArticle()
                    true
                }
            )
        )
    },
    state = rememberSwipeToDismissBoxState(),
    backgroundContent = {}
) {
    ArticleListItem()
}

カスタムのユーザー補助アクションを実装すると、ユーザーはアクション メニューからアクションにアクセスできます。

カスタム アクションの詳細については、カスタム アクションをご覧ください。

利用可能なアクションをわかりやすくする

UI 要素が長押しなどのアクションをサポートしている場合、TalkBack などのユーザー補助サービスは「ダブルタップして長押し」と読み上げます。

この一般的な読み上げでは、長押しアクションの動作に関するコンテキストがユーザーに提供されません。

この読み上げをより有用にするには、アクションに意味のある説明を指定します。

Compose では、clickablecombinedClickable などの標準のインタラクション修飾子に、アクションの説明を提供するために使用できる組み込みパラメータ(onClickLabelonLongClickLabel)があります。 例を次に示します。

var contextMenuPhotoId by rememberSaveable { mutableStateOf<Int?>(null) }
val haptics = LocalHapticFeedback.current
LazyVerticalGrid(columns = GridCells.Adaptive(minSize = 128.dp)) {
    items(photos, { it.id }) { photo ->
        ImageItem(
            photo,
            Modifier
                .combinedClickable(
                    onClick = { activePhotoId = photo.id },
                    onLongClick = {
                        haptics.performHapticFeedback(HapticFeedbackType.LongPress)
                        contextMenuPhotoId = photo.id
                    },
                    onLongClickLabel = stringResource(R.string.open_context_menu)
                )
        )
    }
}
if (contextMenuPhotoId != null) {
    PhotoActionsSheet(
        photo = photos.first { it.id == contextMenuPhotoId },
        onDismissSheet = { contextMenuPhotoId = null }
    )
}

これにより、TalkBack は「コンテキスト メニューを開く」と読み上げ、ユーザーはアクションの目的を理解できます。

semantics 修飾子でラベルを直接指定することもできます。

タップとクリックへの応答の詳細については、 タップと押下インタラクティブな要素をご覧ください。

組み込みのユーザー補助機能を使用する

アプリの UI を設計する際は、組み込みのユーザー補助機能を利用して、既存の機能を再実装しないようにします。Material、Compose UI、Foundation API は、デフォルトで多くのユーザー補助機能を実装して提供しています。

Jetpack Compose では、ButtonSwitchCheckbox などの組み込みのコンポーザブルを使用して、ユーザー補助に対応した UI を作成します。これらのコンポーネントには、rolestateDescription などの semantics 修飾子がプリパッケージされており、これらを使用してアプリのユーザー補助機能を強化できます。

カスタム コンポーネントにセマンティクスを適用する

カスタム コンポーネントを作成する場合は、そのコンポーネントが役割を果たすためにどのようなユーザー補助サポートが必要かを考慮してください。多くの場合、すでに使用している標準の Compose API(clickabletoggleableselectable など)で十分です。これらの API は、セマンティクス ツリーを自動的に入力するためです。

ただし、一部のコンポーネントでは、標準の修飾子よりも具体的な情報が必要になります。このような場合は、特殊な修飾子(triStateToggleable など)を探します。存在しない場合は、低レベルの Modifier.semantics を使用してセマンティクスを明示的に指定します。

たとえば、3 つの状態(オン、オフ、未確定)を持つスイッチ TriStateSwitch を考えてみましょう。

標準の toggleable 修飾子は 2 つの状態を想定していますが、triStateToggleable 修飾子は 3 番目の状態の複雑さを処理します。ユーザー補助の RoleSwitch)と State を自動的に設定します。これにより、ユーザー補助サービスは正確な情報を受け取り、セマンティクスを手動で定義する必要がなくなります。

次のコード スニペットは、このアプローチを使用した TriStateSwitch を示しています。

@Composable
fun TriStateSwitch(
    state: ToggleableState,
    onClick: () -> Unit,
    modifier: Modifier = Modifier
) {
    // A real implementation would include custom drawing for the switch.
    // This example uses a Box to demonstrate the semantics.
    Box(
        modifier = modifier
            .size(width = 64.dp, height = 40.dp)
            // triStateToggleable handles the semantics (Role and State)
            // automatically, so explicit Modifier.semantics is not needed here.
            .triStateToggleable(
                state = state,
                onClick = onClick,
                role = Role.Switch
            )
            // Add visual feedback based on the state
            .background(
                when (state) {
                    ToggleableState.On -> Color.Green
                    ToggleableState.Off -> Color.Gray
                    ToggleableState.Indeterminate -> Color.Yellow
                }
            )
    )
}

// Usage within another composable:
var state by remember { mutableStateOf(ToggleableState.Off) }
TriStateSwitch(
    state = state,
    onClick = {
        state = when (state) {
            ToggleableState.Off -> ToggleableState.Indeterminate
            ToggleableState.Indeterminate -> ToggleableState.On
            ToggleableState.On -> ToggleableState.Off
        }
    }
)

カスタム コンポーネントを構築する場合は、ユーザー補助のために関連するすべてのセマンティック プロパティを指定してください。たとえば、コンポーネントがスイッチやボタンなどの標準コントロールを模倣している場合、これらのプロパティには、コンポーネントのロール(Role.SwitchRole.Button など)、stateDescription(「オン」、「オフ」、「チェック済み」、「未チェック」など)、関連するアクション ラベルが含まれます。詳細については、カスタム コンポーネントをご覧ください。

色以外の手がかりも取り入れる

色覚障がいのあるユーザーをサポートするには、アプリ画面内の UI 要素を区別するのに、色以外の手がかりを 使用してください。そのテクニックとして、形やサイズを変える、テキストまたは視覚的なパターンを示す、音声またはタップ(触覚)に基づくフィードバックを追加する方法などにより、要素を区別します。

図 1 に、あるアクティビティの 2 つのバージョンを示します。一方のバージョンでは、ワークフロー内の可能な 2 つのアクションを、色だけで区別しています。もう一方のバージョンでは、 おすすめの方法を取り入れて、色だけでなく、形とテキストによって、 2 つのアクションの違いを強調しています。

左側は、緑と赤の 2 つの丸いボタンがある画面です。右側の画面は同じですが、2 つの丸いボタンにはテキストと意味のあるアイコンが表示されています。
図 1.色だけ (左)と色、形、テキスト(右)を使った UI 要素の作成例。

メディア コンテンツのユーザー補助機能を強化する

動画クリップ や音声録音などのメディア コンテンツを含むアプリを開発する場合、そうしたコンテンツを把握する際のさまざまなユーザー補助のニーズ に応じるサポートを試みてください。特に、次のことを試してください。

  • メディアの一時停止または停止、音量の変更、字幕(キャプション)の切り替えをユーザーが行えるようにするコントロールを含めます。
  • ワークフローの完了に不可欠な情報を動画が提示する場合、 同じ内容を代替形式で提供します。文字起こしのように、

参考情報

アプリのユーザー補助機能を強化する方法について詳しくは、以下の参考情報をご覧ください。

Codelab

Views のコンテンツ