1. 始める前に
この Codelab では、Jetpack Compose を使用してアプリでスクロール可能なリストを作成する方法を学びます。
アファメーションのリストを日常をポジティブにする美しい画像とともに表示する Affirmations アプリを取り扱います。
データはすでに用意されているので、そのデータを取得して UI に表示するだけです。
前提条件
- Kotlin のリストに精通していること
- Jetpack Compose でレイアウトを作成した経験
- デバイスまたはエミュレータでアプリを実行した経験
学習内容
- Jetpack Compose を使用してマテリアル デザイン カードを作成する方法
- Jetpack Compose を使用してスクロール可能なリストを作成する方法
作成するアプリの概要
- 既存のアプリケーションをベースとして、UI にスクロール可能なリストを追加する
最終的なプロダクトは次のようになります。

必要なもの
- インターネットにアクセスできるパソコン、ウェブブラウザ、Android Studio
- GitHub へのアクセス
スターター コードをダウンロードする
Android Studio で basic-android-kotlin-compose-training-affirmations フォルダを開きます。
アプリが starter ブランチコードからビルドされた場合、空白の画面を表示することが想定されています。

2. リストアイテムのデータクラスを作成する
アファメーション用のデータクラスを作成する
Android アプリでは、リストはリストアイテムで構成されます。単一のデータを持つリストアイテムの場合、これは文字列や整数などの単純なアイテムになります。画像とテキストなど、複数のデータを持つリストアイテムの場合、それらすべてのプロパティを格納するクラスが必要になります。データクラスはプロパティのみを格納するクラスの一種で、このようなプロパティを扱うユーティリティ メソッドを提供します。
- com.example.affirmations の下に新しいパッケージを作成します。

新しいパッケージに model という名前を付けます。この model パッケージには、データクラスで表されるデータモデルが含まれます。このデータクラスは、「アファメーション」となるものに関連する情報を表すプロパティで構成されます。アファメーションは、文字列リソースと画像リソースを 1 つずつ含みます。パッケージとは、クラスと他のディレクトリを含むディレクトリのことです。

- com.example.affirmations.model パッケージ内に新しいクラスを作成します。

新しいクラスに Affirmation という名前を付け、これを Data Class にします。

- 各 Affirmationは、1 つの画像と 1 つの文字列で構成されます。Affirmationデータクラスに 2 つのvalプロパティを作成します。一つはstringResourceId、もう一つはimageResourceIdという名前にします。どちらも整数にする必要があります。
Affirmation.kt
data class Affirmation(
    val stringResourceId: Int,
    val imageResourceId: Int
)
- stringResourceIdプロパティに- @StringResアノテーションを付け、- imageResourceIdに- @DrawableResアノテーションを付けます。- stringResourceIdは、文字列リソースに格納されているアファメーション テキストの ID を表します。- imageResourceIdは、ドローアブル リソースに格納されているアファメーション画像の ID を表します。
Affirmation.kt
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
data class Affirmation(
    @StringRes val stringResourceId: Int,
    @DrawableRes val imageResourceId: Int
)
- com.example.affirmations.data パッケージで Datasource.kt ファイルを開き、2 つの import ステートメントと Datasourceクラスのコンテンツのコメント化を解除します。
Datasource.kt
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource() {
    fun loadAffirmations(): List<Affirmation> {
        return listOf<Affirmation>(
            Affirmation(R.string.affirmation1, R.drawable.image1),
            Affirmation(R.string.affirmation2, R.drawable.image2),
            Affirmation(R.string.affirmation3, R.drawable.image3),
            Affirmation(R.string.affirmation4, R.drawable.image4),
            Affirmation(R.string.affirmation5, R.drawable.image5),
            Affirmation(R.string.affirmation6, R.drawable.image6),
            Affirmation(R.string.affirmation7, R.drawable.image7),
            Affirmation(R.string.affirmation8, R.drawable.image8),
            Affirmation(R.string.affirmation9, R.drawable.image9),
            Affirmation(R.string.affirmation10, R.drawable.image10))
    }
}
3. アプリにリストを追加する
リストアイテム カードを作成する
このアプリはアファメーションのリストを表示することを想定しています。リストを表示するための UI を構成する最初のステップとして、リストアイテムを作成します。各アファメーション アイテムは 1 つの画像と 1 つの文字列で構成されます。これらの各アイテムのデータにはスターター コードが付属しています。このようなアイテムを表示するために、UI コンポーネントを作成します。
アイテムは、Image コンポーザブルと Text コンポーザブルを含む Card コンポーザブルで構成されます。Compose における Card は、コンテンツとアクションを単一のコンテナで表示するサーフェスです。プレビューで、アファメーション カードは次のようになります。

カードには、画像と、その下にテキストが表示されます。この縦型のレイアウトは、Card コンポーザブルでラップされた Column コンポーザブルを使用することで実現できます。自分で試してみるか、以下の手順に沿って作成してください。
- MainActivity.kt ファイルを開きます。
- AffirmationsApp()メソッドの下に- AffirmationCard()という新しいメソッドを作成し、- @Composableアノテーションを付けます。
MainActivity.kt
@Composable
fun AffirmationsApp() {
}
@Composable
fun AffirmationCard() {
}
- メソッド シグネチャを編集して、Affirmationオブジェクトをパラメータとして取得します。Affirmationオブジェクトはmodelパッケージのものです。
MainActivity.kt
import com.example.affirmations.model.Affirmation
@Composable
fun AffirmationCard(affirmation: Affirmation) {
}
- 署名に modifierパラメータを追加します。パラメータのデフォルト値Modifierを設定します。
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
}
- AffirmationCardメソッド内で、- Cardコンポーザブルを呼び出します。- modifierパラメータを渡します。
MainActivity.kt
import androidx.compose.material3.Card
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
    }
}
- Cardコンポーザブル内に- Columnコンポーザブルを追加します。- Columnコンポーザブル内のアイテムは、UI 上で縦方向に配置されます。これで、関連するテキストの上に画像を配置できます。逆に、- Rowコンポーザブル内のアイテムは横方向に配置されます。
MainActivity.kt
import androidx.compose.foundation.layout.Column
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {
        }
    }
}
- Imageコンポーザブルを- Columnコンポーザブルのラムダ本文内に追加します。- Imageコンポーザブルには、表示するリソースと- contentDescriptionが常に必要です。リソースは、- painterパラメータに渡される- painterResourceである必要があります。- painterResourceメソッドは、ベクター型ドローアブルか、PNG などのラスター化されたアセット形式を読み込みます。また、- contentDescriptionパラメータとして- stringResourceを渡します。
MainActivity.kt
import androidx.compose.foundation.Image
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {
            Image(
                painter = painterResource(affirmation.imageResourceId),
                contentDescription = stringResource(affirmation.stringResourceId),
            )
        }
    }
}
- painterパラメータと- contentDescriptionパラメータに加えて、- modifierと- contentScaleを渡します。- contentScaleは、画像の拡大方法と表示方法を決定します。- Modifierオブジェクトの- fillMaxWidth属性を設定して、高さを- 194.dpにする必要があります。- contentScaleは、- ContentScale.Cropである必要があります。
MainActivity.kt
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.unit.dp
import androidx.compose.ui.layout.ContentScale
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {
            Image(
                painter = painterResource(affirmation.imageResourceId),
                contentDescription = stringResource(affirmation.stringResourceId),
                modifier = Modifier
                    .fillMaxWidth()
                    .height(194.dp),
                contentScale = ContentScale.Crop
            )
        }
    }
}
- Column内で、- Imageコンポーザブルの後に- Textコンポーザブルを作成します。- affirmation.stringResourceIdの- stringResourceを- textパラメータに渡し、- padding属性を- 16.dpに設定した- Modifierオブジェクトを渡します。また、- MaterialTheme.typography.headlineSmallを- styleパラメータに渡してテキストテーマを設定します。
MainActivity.kt
import androidx.compose.material3.Text
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.platform.LocalContext
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
    Card(modifier = modifier) {
        Column {
            Image(
                painter = painterResource(affirmation.imageResourceId),
                contentDescription = stringResource(affirmation.stringResourceId),
                modifier = Modifier
                    .fillMaxWidth()
                    .height(194.dp),
                contentScale = ContentScale.Crop
            )
            Text(
                text = LocalContext.current.getString(affirmation.stringResourceId),
                modifier = Modifier.padding(16.dp),
                style = MaterialTheme.typography.headlineSmall
            )
        }
    }
}
AffirmationCard コンポーザブルのプレビュー
Affirmations アプリの UI の中核となるカードを作成することができました。カードが正しく表示されることを確認するために、アプリ全体を起動せずにプレビューできるコンポーザブルを作成します。
- AffirmationCardPreview()という名前のプライベート メソッドを作成します。メソッドに- @Previewと- @Composableのアノテーションを付けます。
MainActivity.kt
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
private fun AffirmationCardPreview() {
}
- メソッド内で AffirmationCardコンポーザブルを呼び出します。そのコンポーザブルに、コンストラクタに渡されたR.string.affirmation1文字列リソースとR.drawable.image1ドローアブル リソースを使用する新しいAffirmationオブジェクトを渡します。
MainActivity.kt
@Preview
@Composable
private fun AffirmationCardPreview() {
    AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1))
}
- [Split] タブを開くと、AffirmationCardのプレビューが表示されます。必要に応じて、[Design] ペインで [Build & Refresh] をクリックしてプレビューを表示します。

リストを作成する
リストアイテムのコンポーネントがリストの唯一のビルディング ブロックです。リストアイテムを作成したら、それを利用してリスト コンポーネントそのものを作成できます。
- AffirmationList()という関数を作成し、- @Composableアノテーションを付けて、- Affirmationオブジェクトの- Listをメソッド シグネチャのパラメータとして宣言します。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>) {
    
}
- デフォルト値を Modifierにして、メソッド シグネチャのパラメータとしてmodifierオブジェクトを宣言します。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
}
- Jetpack Compose では、LazyColumnコンポーザブルを使用してスクロール可能なリストを作成できます。LazyColumnとColumnの違いは、表示するアイテム数が少ない場合はColumnを使用する必要がある点です(Compose は一度にすべてのアイテムを読み込むため)。Columnには、事前に定義した(つまり一定の)数のコンポーザブルのみを格納できます。LazyColumnはオンデマンドでコンテンツを追加できるため、長いリスト、特にリストの長さが不明な場合に適しています。LazyColumnもデフォルトでスクロール機能を提供します。追加のコードは必要ありません。AffirmationList()関数内でLazyColumnコンポーザブルを宣言します。modifierオブジェクトを引数としてLazyColumnに渡します。
MainActivity.kt
import androidx.compose.foundation.lazy.LazyColumn
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {
    }
}
- LazyColumnのラムダ本体で、- items()メソッドを呼び出して- affirmationListを渡します。- items()メソッドは、アイテムを- LazyColumnに追加するためのものです。このメソッドは、このコンポーザブルに固有のもので、他のコンポーザブルでは一般的ではありません。
MainActivity.kt
import androidx.compose.foundation.lazy.items
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {
        items(affirmationList) {
        }
    }
}
- items()メソッドの呼び出しにはラムダ関数が必要です。この関数で、- affirmationListの 1 つのアファメーション アイテムを表す- affirmationのパラメータを指定します。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {
        items(affirmationList) { affirmation ->
        }
    }
}
- リスト内のアファメーションごとに AffirmationCard()コンポーザブルを呼び出します。affirmationと、padding属性を8.dpに設定したModifierオブジェクトを渡します。
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
    LazyColumn(modifier = modifier) {
        items(affirmationList) { affirmation ->
            AffirmationCard(
                affirmation = affirmation,
                modifier = Modifier.padding(8.dp)
            )
        }
    }
}
リストを表示する
- AffirmationsAppコンポーザブルで、現在のレイアウトの向きを取得し、変数に保存します。これらは、後でパディングを設定するために使用されます。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
}
- 次に、Surfaceコンポーザブルを作成します。このコンポーザブルは、AffirmationsListコンポーザブルのパディングを設定します。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
    Surface() {
    }
}
- 親の最大幅と最大高さを埋め、ステータスバーのパディングを設定し、左右のパディングを layoutDirectionに設定するModifierをSurfaceコンポーザブルに渡します。たとえば、LayoutDirectionオブジェクトをパディングに変換する場合は、WindowInsets.safeDrawing.asPaddingValues().calculateStartPadding(layoutDirection)のようにします。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
    Surface(
        Modifier = Modifier
        .fillMaxSize()
        .statusBarsPadding()
        .padding(
            start = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateStartPadding(layoutDirection),
            end = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateEndPadding(layoutDirection),
        ),
    ) {
    }
}
- Surfaceコンポーザブルのラムダで、- AffirmationListコンポーザブルを呼び出し、- DataSource().loadAffirmations()を- affirmationListパラメータに渡します。
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
    val layoutDirection = LocalLayoutDirection.current
    Surface(
        Modifier = Modifier
        .fillMaxSize()
        .statusBarsPadding()
        .padding(
            start = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateStartPadding(layoutDirection),
            end = WindowInsets.safeDrawing.asPaddingValues()
                    .calculateEndPadding(layoutDirection),
        ),
    ) {
        AffirmationsList(
            affirmationList = Datasource().loadAffirmations(),
        )
    }
}
デバイスまたはエミュレータで Affirmations アプリを実行すると、完成したプロダクトが表示されます。

4. 解答コードを取得する
この Codelab の完成したコードをダウンロードするには、以下の git コマンドを使用します。
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-affirmations.git $ cd basic-android-kotlin-compose-training-affirmations $ git checkout intermediate
または、リポジトリを ZIP ファイルとしてダウンロードし、Android Studio で開くこともできます。
解答コードを確認する場合は、GitHub で表示します。
5. まとめ
ここでは、Jetpack Compose でカード、リストアイテム、スクロール可能なリストを作成する方法を学習しました。これらはあくまでリスト作成の基本ツールであり、リストアイテムは、創造性を発揮して自由にカスタマイズできます。
概要
-  Cardコンポーザブルを使用してリストアイテムを作成します。
- Cardコンポーザブル内の UI を変更します。
-  LazyColumnコンポーザブルを使用してスクロール可能なリストを作成します。
- カスタムのリストアイテムを使用してリストを作成します。
