LoginSignup
11
6

More than 1 year has passed since last update.

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

Last updated at Posted at 2021-11-29

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

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

固定サイズの場合

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

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

@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)
            }
        }
    }
}

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

@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)))
        }
    }
}

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

サイズが不定の場合

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

@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() で上乗せしてみると上手くいかないことがわかります。

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

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() を追加してあげます。

@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))
                )
            }
        }
    }
}

いい感じにできました💪

11
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
6