6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「モバイルアプリアクセシビリティ入門」に登場するAndroidのAPIのCompose版紹介

Posted at

「モバイルアプリアクセシビリティ入門」に記載されている Android の API は View のもので、Jetpack Compose だとどのようになるのか置き換え先の紹介になります。
あくまで API の紹介だけなので、具体的な使い方は本を読んでください。

6.3/タップ領域を確保する

Modifier#minimumInteractiveComponentSize が用意されており、これを適用するとシステム上で必要なタッチターゲットサイズ分のレイアウトサイズが確保されます。
デフォルトが 48dp で設定されています。

Text(
    text = "Button",
    modifier = Modifier
        .clickable { ... }
        .minimumInteractiveComponentSize()
)

システム上でサイズが設定される minimumInteractiveComponentSize ですが、Android XR では 56dp が必要なタッチターゲットサイズになるので、この API を使うと XR 上では変わる可能性がありえそうです。(Jetpack Compose for XR 1.0.0-alpha01 ではそのような変更は入っていない)

6.4/contentDescription

IconImage のような画像を表示する Composable fun には必須の引数になっています。
読み上げが必要ない場合は null を渡すようにしましょう。

Image(
    painter = painterResource(R.drawable.sample),
    contentDesctiprion = "サンプル画像"
)

Icon(
    painter = painterResource(R.drawable.sample),
    contentDesctiprion = null
)

IconImage 以外の場合は Modifier#semantics から contentDescription を設定します。

Text(
    text = "下の図をご覧ください",
    modifier = Modifier.semantics {
        contentDescription = "次の画像をご覧ください"
    }
)

Modifier#semantics による contentDescription の設定は Composable fun が本来持っていた読み上げ内容を上書きしてしまうため注意が必要です。
IconImageCanvas など、記述することが本質的に困難な場合に適用しましょう。

6.4/importantForAccessibility

IconImage の場合は contentDescription の引数に null を渡すと読み上げさせないことができます。空文字の場合は空文字が読み上げられるので注意が必要です。
またコンポーネントに対してフォーカスを移動させずに読み上げさせない場合は Modifier#semanticsinvisibleToUser を設定するか Modifier#clearAndSetSemantic を設定します。

Icon(
    painter = painterResource(R.drawable.sample),
    contentDesctiprion = null
)

Text(
    text = "Disabled",
    modifier = Modifier.semantics {
        invisibleToUser()
    }
)

Button(
    modifier = Modifier.clearAndSetSemantics {
    }
) {
    ...
}

Modifier#semanticsinvisibleToUser は Compose 1.8.0 以降 deprecated になることが予定されており、hideFromAccessibility に置き換わります。
名前の変更のみで挙動の差はないです。

6.4/labelFor

compose-material や compose-material3 標準の TextField/OutlinedTextField であれば特別な設定なしに labelFor 相当の動きがされます。
相当の動きでしかなく labelFor のようにラベルとプレースホルダーを繋いで読み上げてはくれません。
また、標準の TextField/OutlinedTextField を使わない場合 Compose での API は現時点(1.7.7)でないので実装で labelFor 相当の読み上げの実装が必要になります。

var text by remember { mutableStateOf("") }
TextField(
    modifier = Modifier.fillMaxWidth(),
    value = text,
    label = { Text("名前") },
    placeholder = { Text("入力してください") },
    onValueChange = {
        text = it
    }
)

6.4/screenReaderFocusable

Modifier.semantics(mergeDescendants = true) で子をまとめて一括に読み上げさせることができます。

Column(
    modifier = Modifier.semantics(mergeDescendants = true) {}
) {
    Text("1行目")
    Text("2行目")
}

6.4/accessibilityHeading

Modifier#semanticsheading() を設定します。

Column(
    modifier = Modifier.semantics {
        heading()
    }
) {
    Text("Header")
}

6.4/accessibilityPaneTitle

Modifier#semanticspaneTitle を設定します。

Dialog(
    onDismissRequest,
) {
    Column(
        Modifier.semantics {
            paneTitle = "この枠内には重要な情報が含まれています"
        }
    ) {
        ...
    }
}

6.4/accessibilityTraversalBeforeとaccessibilityTraversalAfter

Compose では accessibilityTraversalBefore と accessibilityTraversalAfter の代わりになる API が View よりも柔軟に対応できるようになっています。
Modifier#semantics から isTraversalGroup を設定することで要素のグルーピングをすることが可能になります。

Row {
    Column(Modifier.semantics { isTraversalGroup = true }) {
        Text("これは")
        Text("左のテキストです")
    }
    Column(Modifier.semantics { isTraversalGroup = true }) {
        Text("これは")
        Text("右のテキストです")
    }
}

isTraversalGroup と組み合わせて使用する traversalIndex で読み上げの順序を細かくカスタマイズすることができます。

Scaffold(
    topBar = { TopAppBar(title = { ... }) },
    floatingActionButton = {
        Box(
            modifier = Modifier.semantics { 
                isTraversalGroup = true 
                traversalIndex = -1f 
            }
        ) {
            FloatingActionButton(onClick = {}) {
                Icon(imageVector = Icons.Default.Add, contentDescription = "Add")
            }
        }
    },
) {
    ...
}

6.4/accessibilityLiveRegion

Modifier#semanticsaccessibilityLiveRegion 同様に liveRegion を設定します。

Text(
    modifier = Modifier.semantics {
        liveRegion = LiveRegionMode.Polite // or LiveRegionMode.Assertive
    }
)


その他の本では紹介されていない Compose におけるアクセシビリティ対応の具体的な実装例は公式ドキュメントを参照することをお勧めします。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?