Android Basic with ComposeのUnit3で学んだことをまとめてみる: ScrollableList/アクセシビリティ
はじめに
こんにちは、某SIerでSEをやっているnekorush14です。
この記事は絶賛再*n入門しているAndroid開発について、Google公式のLearning Courseを通して学んだことをアウトプットするシリーズです。
Jetpack Composeに関するCourseのUnit3で得た知見を話します。
前回の記事はこちら👇
Unit 3: Display lists and use Material Design
このユニットでは、UIのコンポーネントで基本的な要素であるリストについて、Scrollable List(スクロール可能なリスト)と簡単なアニメーションを扱います。
また、Jetpack ComposeでMaterial Design(特にMaterial 3)を扱う方法について学びます。
今回はUnit3で扱われたScrollable Listとアクセシビリティについてまとめます。
Scrollable list
Jetpack ComposeではLazyColumn
Composableを使用してスクロール可能なリストを定義します。Android ViewにおけるRecyclerViewに相当します。
リストを表示するにはColumn
とLazyColumn
、Grid形式で表示するGrid
やLazyGrid
などがあります。
これらの使い分けですが、Column
は表示項目が少ない場合に使用します。これは、Composition時にComposeがすべての項目を読み込むため、Column
が定義済み・固定数のComposableを保持するからです。
一方、LazyColumn
はオンデマンドに項目を追加可能であり、不定長のリストに最適です。追加のコードなしでスクロールをデフォルトで提供します。LazyColumn
にリスト項目を定義する場合はLazyColumn
のDSL内でitems()
を呼びます。items()
の引数に追加したい項目のリストを指定することでそのリストの中身をLazy
に表示します。この追加の方式はLazyColumn
Composable特有のもので、他のComposableでは一般的ではありません。
また、LazyVerticalGrid
を使用することでスクロール可能な垂直方向のグリッドリストを表示できます。columns
引数に列数を生成するComposableを指定することで列数を指定できます。GridCells.Adaptive()
を使用すると、指定したサイズに応じてアダプティブに列数が変化します。GridCells.Fixed()
を使用すると、画面サイズにかかわらず引数で指定した固定の列数を表示するようになります。
val samples = listOf("Sample", "List")
LazyColumn(
modifier = Modifier
) {
items(samples) { sample ->
Text(
text = sample
)
}
}
リストに追加するデータのモデルはmodel
パッケージに定義します。(このパッケージに定義する理由はUnit 4で学ぶArchitectureの章で詳しく学びます)
データモデルはKotlinのdata class
を使用して定義します。data class
を使用することでリスト項目の持つプロパティやそのプロパティを操作するユーティリティメソッドを定義できます。また、data class
に集約することでモデルの使いまわしも可能となります。
Launcher icon
アプリアイコンは様々なデバイスの画面密度に対応するため、いくつかの異なるバージョンを用意する必要があります。
resフォルダ内に以下のDpiごとのフォルダが存在するため、対応するサイズのアイコン画像を配置します。
-
mdpi
- 160dpi向け -
hdpi
- 240dpi向け -
xhdpi
- 320dpi向け -
xxhdpi
- 480dpi向け -
xxxhdpi
- 640dpi向け -
nodpi
- 画面のピクセル密度に関係なく、拡大縮小が意図されていないリソース向け -
anydpi
- あらゆるピクセル密度に合わせて拡張可能なリソース向け
Android 8.0 (API 26)以降ではアダプティブアイコンがサポートされています。アダプティブアイコンはForegroundとBackgroundの2レイヤーで構成され、より柔軟性や視覚効果が高まったアイコンです。アダプティブアイコンでは、ForegroundとBackgroundが重ねられたあと、その上から円形などのマスクが適用され、アプリケーションアイコンとなります。
アダプティブアイコンを適用する場合は-v26
が付与されたフォルダに配置する必要があります。これによりAndroid 8.0より前(API 25以前)の場合はmdpi
やxhdpi
などの密度ベースのminimap
フォルダが優先されます。
Defaultで生成されるアイコンForeground
Defaultで生成されるアイコンBackground
アイコンはXML形式のVector画像(SVGファイル)を使用することで劣化させることなく拡張が可能となります。アイコンは単純な形状で構成されているためVector画像として扱いやすいですが、写真などの画像は複雑であるためビットマップ画像として扱ったほうが効率的です。よって、Drawableに定義するアプリ内で表示するための画像はVector画像ではなくビットマップ画像として定義します。
アダプティブアイコンを用いる場合のForegroundとBackgroundは108dpi x 108dpi
である必要があります。アダプティブアイコンの詳細はAdaptiveIconDrawable docsに記載があります。また、Androidアイコンのデザインガイダンスはマテリアルデザインのサイトを参照ください。
アダプティブアイコンを適用する際に注意すべき点は、デバイスメーカーごとにマスクの形状がことなるため、セーフゾーン内にアイコンのコアとなる情報を配置する必要があるということです。この セーフゾーンは中央の直径66dpi
の円であり、この外側にあるコンテンツは切り取られる可能性があります。
アイコンを指定する際にAndroid StudioのImage Asset Studioを使うことで、密度ベースの画像やanydpiのアイコンが自動生成されます。
Image Asset Studio
Accessibility
Androidにはいくつかのアクセシビリティサービスが実装されています。TalkBackはGoogleが提供するスクリーンリーダーでアクセシビリティサービスの1つです。TalkBackを利用することでユーザーは画面を見ずにデバイスが操作できます。特に視覚に障がいのある方にとって重要な機能となります。TalkBackをオンにすると、タップアクションはダブルタップ、スワイプ・システムナビゲーションは2本指を使用する様になります。
SwitchAccessはタッチスクリーンの代わりに1つ以上のデバイスを使用して操作が可能になる機能です。画面上の項目をスキャンし、項目を選択するまでスイッチを押すたびに各項目を順番に強調表示していきます。単純クリックアクションも持つ項目に対して選択したときはタップアクションを実行するのと同義となります。スワイプなどのアクションを持つ項目にはカスタムアクセシビリティアクションを使用して、その項目に対して実行できるアクションを選択します。
アクセシビリティの高いアプリを作るには、UI上で考慮すべき点があります。Content descriptionはスクリーンリーダーが読み上げ対象にする表示項目の説明です。画像などのグラフィカルな情報について説明を提供できます。ComposeではcontentDescription
属性を使用して記述できます。装飾目的の場合はcontentDescription
をnull
に設定します。
Touch target sizeはユーザがタップする画面要素のサイズをさします。アクセシビリティの観点では、画面上の要素に対して確実に操作可能な大きさでなくてはなりません。最小のTouch target sizeは48dp x 48dp
(高さ×幅)です。
Color contrastはその名の通り画面要素のコントラストです。UIの配色はユーザの読みやすさ・理解のしやすさに影響します。コントラストが十分確保されている場合は視覚障がいのある方だけではなく、屋外やディスプレイ輝度が低いなどの極端な照明条におけるUI表示で役立ちます。詳細はColor contrast - Android Accessibility Helpを参照ください。
まとめ
今回はUnit3で扱われたScrollable Listとアクセシビリティについてまとめてみました。Scrollable Listはデータをリストで表示する際によく使う基本的なComposableだと感じました。
また、アクセシビリティはすべてのユーザにアプリを使ってもらうために抑えるべき重要なポイントでした。Jetpack Composeではアクセシビリティに対応するため仕組みが用意されているため、簡単に実装できそうな印象でした。
次回はUnit 3の残りのコンテンツであるMaterial Designについてまとめます。
Discussion