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

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

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

  • TalkBack: 目の不自由な方や視力の弱い方をサポートします。合成音声でコンテンツを読み上げ、ユーザー ジェスチャーに応じてアプリでアクションを実行します。
  • スイッチ アクセス: 運動障がいのある方をサポートします。インタラクティブ要素をハイライト表示し、ユーザーがボタンを押したときにアクションを実行します。1 つまたは 2 つのボタンだけでデバイスを操作できます。

ユーザー補助機能を必要とするユーザーがアプリを適切に使用できるようにするには、このページで説明するベスト プラクティスに沿ってアプリを作成する必要があります。このベスト プラクティスは、アプリのユーザー補助を強化するで説明されているガイドラインに基づいています。

以降のセクションで説明するベスト プラクティスは、アプリのユーザー補助をさらに改善するのに役立ちます。

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

要素にラベルを付ける

アプリ内のインタラクティブな UI 要素ごとに、わかりやすく説明的なラベルをユーザーに提供することが重要です。各ラベルは、特定の要素のセマンティクス(要素の意味と目的)を説明する必要があります。TalkBack などのスクリーン リーダーは、これらのラベルをユーザーに読み上げることができます。

ほとんどの場合、Compose API とマテリアルにはデフォルトのユーザー補助サポートが用意されています。ただし、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 要素が表示される場合は、これらの要素を親コンテナ(Column、Row、Box など)内に配置します。親コンテナの semantics 修飾子を使用して、mergeDescendants を true に設定します。

これにより、ユーザー補助サービスは、内部要素のコンテンツの説明を 1 つずつ、1 つのアナウンスで提示できます。関連する要素を統合すると、支援技術のユーザーが画面上の情報をより効率的に見つけられるようになります。

次のスニペットでは、Row コンポーザブルが親コンテナとして機能します。Row 内には、ブログ投稿のメタデータ(著者のアバター、著者の名前、推定読了時間)を示す関連要素があります。mergeDescendants を true に設定すると、これらの内部要素がグループ化され、ユーザー補助サービスで 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 は、要素とその子のデフォルトのセマンティクスを完全に消去します。これにより、新しい統合されたユーザー補助要素を定義できます。通常、このアプローチは複雑なカスタム コンポーネントに使用します。

次の例では、Icon と Text は、カスタム切り替え内の装飾的な子要素です。ユーザー補助サービスがこれらの子を個別に走査しないようにするには、親の Row で clearAndSetSemantics を使用して、子のセマンティクスをクリアします。これにより、ユーザー補助サービスは 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.combinedClickable で onClickLabel や onLongClickLabel などのパラメータを使用して、標準のタップ操作にわかりやすいラベルを付けます。

標準のタップにマッピングできない複雑な操作には、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 では、clickable や combinedClickable などの標準的なインタラクション修飾子に、アクションの説明を提供するために使用できる組み込みパラメータ(onClickLabel や onLongClickLabel など)があります。次に例を示します。

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 では、Button、Switch、Checkbox などの組み込みコンポーザブルを使用して、ユーザー補助機能を備えた UI を作成します。これらのコンポーネントには、role や stateDescription などの semantics 修飾子がプリパッケージされており、アプリのユーザー補助を強化するために使用できます。

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

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

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

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

標準の toggleable 修飾子は 2 つの状態を想定していますが、triStateToggleable 修飾子は 3 つ目の状態の複雑さを処理します。ユーザー補助の Role(Switch)と 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.Switch や Role.Button など)、stateDescription(「オン」、「オフ」、「オン」、「オフ」など)、関連するアクション ラベルが含まれます。詳細については、カスタム コンポーネントをご覧ください。

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

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

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

左側は、緑と赤の 2 つの円形ボタンがある画面です。右側は同じ画面ですが、2 つの円形ボタンにテキストと意味のあるアイコンがラベル付けされています。
図 1. 色のみを使用して UI 要素を作成する例(左)と、色、形状、テキストを使用して UI 要素を作成する例(右)。

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

動画クリップや音声録音などのメディア コンテンツを含むアプリを開発する場合は、さまざまな種類のユーザー補助機能を必要とするユーザーがコンテンツを理解できるようにサポートしてください。特に、次のことを試してください。

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

参考情報

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

Codelab

コンテンツを閲覧する