【Android】Jetpack Composeで、表示させたいURLの画像をImageに渡す方法

# アプリを作っていて・・・

ユーザーが保存した画像を、アイコンとして表示させたいなと思っていました。
ところが、今までアプリの内部で保存されていた画像リソースを参照して表示するくらいの機能しか作ったことがありませんでした。

そこで、どうやったら画像URLをアプリ上で表示できるようになるかを調べたので、今後の自分への忘備録として記しておこうと思います。

今回は執筆時点のバージョンが**2.2.2**の**Coil**ライブラリを使用した場合の解説となりますので、あらかじめご了承ください。

# 画像を読み込むために必要なライブラリのインポート

外部URLに存在する画像を読み取るためには、**Coil**ライブラリが必要になります。

```gradle
implementation("io.coil-kt:coil:2.2.2")
```

https://coil-kt.github.io/coil/compose/

続いて、Jetpack ComposeにてCoilを使いたいので、次のライブラリをインポートします。

```gradle
implementation("io.coil-kt:coil-compose:2.2.2")
```

これで、画像URLを読み込むために必要な準備は整いました。

# 雛形のコンポーザブルを作成する

では、実際に`Image`コンポーザブルで読み込んだ画像URLを表示するようにしていきたいのですが、なにもないとイメージがわかないと思うので、次のようなコンポーザブルを作成しました。

```kotlin
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MemberListItem(
    name: String,
    group: String,
    checked: Boolean = false,
    enabled: Boolean = true,
    onClick: () -> Unit = {}
) {
    ListItem(
        modifier = Modifier
            .clickable {
                if (enabled) {
                    onClick()
                }
            },
        leadingContent = {
            Box(
                modifier = Modifier
                    .size(48.dp)
                    .clip(RoundedCornerShape(100))
                    .background(MaterialTheme.colorScheme.surfaceVariant)
            )
        },
        headlineText = {
            Text("$name")
        },
        supportingText = {
            Row {
                Text("$group")
            }
        },
        trailingContent = {
            if (checked) {
                Icon(
                    Icons.Outlined.Check,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.primary
                )
            } else {
                Icon(
                    Icons.Outlined.Close,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.error
                )
            }
        }
    )
}
```

これをレンダリングした状態は次のようになります。

![名称未設定のデザイン (26).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/631db441-db38-495b-627d-f3ac535a6c7d.png)

# URLの画像をImageコンポーザブルで表示する

上記の画像の、丸いアイコンの部分に画像を表示させたいと思います。
もし、URLが渡されなかった場合は今まで通り`Box`コンポーザブルを表示することとします。

```kotlin
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MemberListItem(
    imageUrl: String? = null,
    name: String,
    group: String,
    checked: Boolean = false,
    enabled: Boolean = true,
    onClick: () -> Unit = {}
) {
    ListItem(
        modifier = Modifier
            .clickable {
                if (enabled) {
                    onClick()
                }
            },
        leadingContent = {
            if (imageUrl == null || imageUrl == "") {
                Box(
                    modifier = Modifier
                        .size(48.dp)
                        .clip(RoundedCornerShape(100))
                        .background(MaterialTheme.colorScheme.surfaceVariant)
                )
            } else {
                Image(
                    painter = rememberAsyncImagePainter(imageUrl),
                    contentDescription = null,
                    modifier = Modifier
                        .size(48.dp)
                        .clip(RoundedCornerShape(100)),
                    contentScale = ContentScale.Crop
                )
            }
        },
        headlineText = {
            Text("$name")
        },
        supportingText = {
            Row {
                Text("$group")
            }
        },
        trailingContent = {
            if (checked) {
                Icon(
                    Icons.Outlined.Check,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.primary
                )
            } else {
                Icon(
                    Icons.Outlined.Close,
                    contentDescription = null,
                    tint = MaterialTheme.colorScheme.error
                )
            }
        }
    )
}
```

注目すべき部分は、`Image`コンポーザブルの`painter`引数に渡している部分です。

ローカルに保存されている画像リソースを表示させたい場合は次のようにしていたと思います。

```kotlin
Image(
    painter = painterResource(imageResourceId),
    ...
)
```

ですが、Coilを使って画像URLを表示させたい場合には、`rememberAsyncImagePainter()`を使います。

```kotlin
Image(
    painter = rememberAsyncImagePainter(imageUrl),
    ...
)
```

実際に画像が表示された状態が次のものになります。

![名称未設定のデザイン (27).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577119/11655b7c-ef6c-82e1-9601-3e3de43e0cfb.png)

# まとめ

Jetpack ComposeではMaterial3の`ListItem`コンポーザブルが提供されており、引数にコンポーザブルを渡すだけで、簡単にリストの要素を構築することができるようになっています。

今まで既存の画像リソースのみを表示することに徹していて、そろそろ画像URLを表示してみたいなと思っていた方は是非Coilを使って実際に画像URLを表示させてみてください。とても簡単です。

# 参考にした記事

https://stackoverflow.com/questions/66957702/how-to-load-image-from-url-in-jetpack-compose