【Jetpack Compose】Composeをオーバーレイ表示する

要素の上に半透明で表示するオーバーレイ表示をしてみました。
サイズが固定の場合はとても簡単なのですが、サイズが不定の場合はちょっとコツ（？）が必要でした。

また、オーバーレイと言っても色々あると思うのですが、この記事で扱うのは要素の上に同じサイズで被せるオーバーレイです。
下の画像のカードラベル表示のComposeに対して、半透明の白色のComposeをオーバーレイ表示しています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166629/a1045912-6a92-f7c3-1d35-ea4cd2dd59d9.png" width=320 />

## 固定サイズの場合

固定サイズの場合は、そのComposeの上に `fillMaxSize()` で半透明のComposeを重ねるだけです。

例えば、こんなカード表示のComposeの場合です。
横幅は引数のModifierで指定できますが、縦幅は80dpで固定指定になっています。

```kotlin
@Composable
fun Card(modifier: Modifier = Modifier) {
    Card(modifier = modifier.height(80.dp), shape = RoundedCornerShape(8.dp), elevation = 4.dp) {
        Row(modifier = Modifier.fillMaxWidth()) {
            Image(
                painter = rememberImagePainter("https://placehold.jp/3d4070/ffffff/80x80.png?text=Image"),
                contentDescription = null,
                modifier = Modifier.size(80.dp)
            )

            Column(modifier = Modifier
                .fillMaxSize()
                .padding(8.dp)) {
                Text("Title", fontSize = 22.sp)
                Text("description", fontSize = 16.sp)
            }
        }
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166629/2e648e67-a2c7-ab0f-6df2-7c023b8b00ba.png" width=320 />

こういうサイズが中身の要素に関わらず固定の場合は、 `fillMaxSize()` で上乗せしてあげればすんなり実装できます。

```kotlin
@Composable
fun Card(modifier: Modifier = Modifier, isOverlay: Boolean = false) {
    Card(modifier = modifier.height(80.dp), shape = RoundedCornerShape(8.dp), elevation = 4.dp) {
        Row(modifier = Modifier.fillMaxWidth()) {
            Image(
                painter = rememberImagePainter("https://placehold.jp/3d4070/ffffff/80x80.png?text=Image"),
                contentDescription = null,
                modifier = Modifier.size(80.dp)
            )

            Column(modifier = Modifier
                .fillMaxSize()
                .padding(8.dp)) {
                Text("Title", fontSize = 22.sp)
                Text("description", fontSize = 16.sp)
            }
        }

        // オーバーレイ
        if (isOverlay) {
            Box(modifier = Modifier
                .fillMaxSize()
                .background(Color(0x88FFFFFF)))
        }
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166629/f291daa1-4bd9-ef11-502d-093eb5b25b0a.png" width=320 />


半透明は白に対してアルファ値を下げてあげれば透過します。白透過でなくて黒透過にしたければ、適当に `0x80000000` とか指定すればできます。

## サイズが不定の場合

今度はサイズが不定の場合です。こういう感じで、テキストによってサイズが高さが可変するケースです。
（Imageあたりのデザインがあれなのは目をつぶります）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166629/619f877b-277c-f780-f7e6-3a93b7f0ff0e.png" width=320 />

```kotlin
@Composable
fun Card(modifier: Modifier = Modifier, description: String) {
    Card(
        modifier = modifier.wrapContentHeight(),
        shape = RoundedCornerShape(8.dp),
        elevation = 4.dp
    ) {
        Row(modifier = Modifier.fillMaxWidth()) {
            Image(
                painter = rememberImagePainter("https://placehold.jp/3d4070/ffffff/80x80.png?text=Image"),
                contentDescription = null,
                modifier = Modifier.size(80.dp)
            )

            Column(
                modifier = Modifier
                    .wrapContentHeight()
                    .padding(8.dp)
            ) {
                Text("Title", fontSize = 22.sp)
                Text(description, fontSize = 16.sp, softWrap = true)
            }
        }
    }
}
```

この場合、先程と同様に `fillMaxSize()` で上乗せしてみると上手くいかないことがわかります。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166629/29a4abf3-3bd5-5519-aab7-ea77ce3fc778.png" width=320 />

こんな感じで、子のBoxのサイズが親のCardのサイズを広げてしまうような挙動になってしまっています。
Overlay表示するBoxのサイズは、親のサイズと同じサイズになってほしいところです。汎用的なModifierには残念ながらそういうものはないのですが、BoxScope限定で使えるModifierに `matchParentSize()` を使えば実現できます。

```kotlin
Box {
    // Boxの子要素限定で使えるModifier
    // Box サイズに影響を与えずに子を親のBoxと同じサイズにする
    Box(modifier = Modifier.matchParentSize()) {}
}
```

しれっと下記のドキュメントにも記載されてます。
https://developer.android.com/jetpack/compose/layouts/basics?hl=ja#type-safety

このModifierを使うにはBoxScopeである必要があるので、Cardの直下にBoxを置いてあげます。そしてOverlay表示しているBoxのmodifierに `matchParentSize()` を追加してあげます。

```kotlin
@Composable
fun Card(modifier: Modifier = Modifier, description: String, isOverlay: Boolean = false) {
    Card(
        modifier = modifier.wrapContentHeight(),
        shape = RoundedCornerShape(8.dp),
        elevation = 4.dp
    ) {
        Box(Modifier.fillMaxWidth()) {
            Row(modifier = Modifier.fillMaxWidth()) {
                Image(
                    painter = rememberImagePainter("https://placehold.jp/3d4070/ffffff/80x80.png?text=Image"),
                    contentDescription = null,
                    modifier = Modifier.size(80.dp)
                )

                Column(
                    modifier = Modifier
                        .wrapContentHeight()
                        .padding(8.dp)
                ) {
                    Text("Title", fontSize = 22.sp)
                    Text(description, fontSize = 16.sp, softWrap = true)
                }
            }

            if (isOverlay) {
                Box(
                    modifier = Modifier
                        // 親のサイズいっぱいに広げる
                        .matchParentSize()
                        .background(Color(0x88FFFFFF))
                )
            }
        }
    }
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166629/cac2ee2e-dd90-0135-7806-b6522d44138b.png" width=320 />

いい感じにできました💪