💬

Jetpack Compose で背景画像を repeat させる

2022/03/08に公開

Android で背景画像を repeat させるには、以下のように実装します。[1]

tile_background.xml
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:antialias="true"
    android:dither="false"
    android:filter="false"
    android:gravity="fill"
    android:src="@android:drawable/alert_dark_frame"
    android:tileMode="repeat" />
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/tile_background" />

ビルド結果は以下のようになります。

ですが、これを Jetpack Compose でやるとなった場合、残念ながら対応する Composable は用意されていません(2022 年 3 月 4 日時点)。

解決策

以下のように AndroidView を用意して、その中で背景画像を repeat させるようにします。

TiledImage.kt
@Composable
fun TiledImage(
    modifier: Modifier = Modifier,
    @DrawableRes id: Int,
    contentDescription: String? = null
) {
    AndroidView(
        modifier = modifier
            .semantics {
                contentDescription?.let {
                    this.contentDescription = it
                }
            },
        factory = {
            val bitmapDrawable = BitmapDrawable(it.resources, BitmapFactory.decodeResource(it.resources, id)).apply {
                tileModeX = Shader.TileMode.REPEAT
                tileModeY = Shader.TileMode.REPEAT
            }
            View(it).apply {
                background = bitmapDrawable
            }
        }
    )
}

@Preview(showBackground = true)
@Composable
private fun Preview() {
    TiledImage(id = R.drawable.alert_dark_frame)
}

ポイントとしては、BitmapDrawable を生成し、tileModeX および tileModeYShader.TileMode.REPEAT を設定することです。

factory = {
    val bitmapDrawable = BitmapDrawable(it.resources, BitmapFactory.decodeResource(it.resources, id)).apply {
        tileModeX = Shader.TileMode.REPEAT
        tileModeY = Shader.TileMode.REPEAT
    }
    View(it).apply {
        background = bitmapDrawable
    }
}

こちらは任意ですが、contentDescription を設定してテストしやすいように実装するのがおすすめです。

// contentDescriptionを設定してテストしやすいように
modifier = modifier
    .semantics {
        contentDescription?.let {
            this.contentDescription = it
        }
    }

プレビュー結果は以下のようになります。

もっとより良い方法がありましたらご指摘ください。

脚注
  1. Y.A.M の 雑記帳: Android 背景画像を repeat させる より引用。 ↩︎

Discussion