🤖

Jetpack Composeでサイズを取得する

2023/03/08に公開

Jetpack Composeでレイアウトを組んでいて要素のサイズを取得することが最近続いたので備忘的に記事化

  • Max(Min)XXXの制約を取得する
  • Modifier.onGloballyPositionedで取得
  • Modifier.layoutで取得

を紹介します。

Max(Min)XXXの制約を取得する

みんな大好きBoxWithConstraintsを使います。

Boxが二つ入ってるColumnBoxWithConstraintsで囲んでみます。

BoxWithConstraints(modifier.background(Color.Red)) {
        val max = maxHeight
        val min = minHeight
        Column(
            Modifier
                .width(80.dp)
        ) {
            Box(modifier = Modifier.height(20.dp).fillMaxWidth().background(color = Color.Blue))
            Box(modifier = Modifier.height(20.dp).fillMaxWidth().background(color = Color.Green))
        }
    }

これでColumn内のBoxの高さ40dpが取得できると思いがちですが、
あくまでmax/minの制約しか取得できないので、この場合は端末の高さが取得されてしまいます。
※親のComposableは存在しない前提

Modifier.onGloballyPositionedで取得

BoxWithConstraintsと同じようなレイアウトで高さを取得していきます。

val current = LocalDensity.current
Box(modifier.background(Color.Red)) {
    var globally = 0.dp
    Column(
        Modifier
            .width(80.dp)
            .onGloballyPositioned {
                with(current) { globally = it.size.height.toDp() }
            }
    ) {
        Box(modifier = Modifier
            .height(20.dp)
            .fillMaxWidth()
            .background(color = Color.Blue))
        Box(modifier = Modifier
            .height(20.dp)
            .fillMaxWidth()
            .background(color = Color.Green))
    }
}

重要なのはここだけです。

Modifier.onGloballyPositioned {
    with(current) { globally = it.size.height.toDp() }
}

この方法なら40dpが取得できます。

Modifier.layoutで取得する

こちらも同じレイアウトを使ってModifier.layoutを使ってみます。

val current = LocalDensity.current
Box(modifier.background(Color.Red)) {
    var layout = 0.dp
    Column(
        Modifier
            .width(80.dp)
            .layout { measurable, constraints ->
                val placeable = measurable.measure(constraints)
                with(current) { layout = placeable.height.toDp() }
                layout(placeable.width, placeable.height) {
                    placeable.placeRelative(0, 0)
                }
            }
    ) {
        Box(modifier = Modifier
            .height(20.dp)
            .fillMaxWidth()
            .background(color = Color.Blue))
        Box(modifier = Modifier
            .height(20.dp)
            .fillMaxWidth()
            .background(color = Color.Green))
    }
}

こちらもメインの実装はこんな感じです。

Modifier.layout { measurable, constraints ->
    val placeable = measurable.measure(constraints)
    with(current) { layout = placeable.height.toDp() }
    layout(placeable.width, placeable.height) {
        placeable.placeRelative(0, 0)
    }
}

こちらは本来カスタムレイアウトを作成するための物なので、onGloballyPositionedを使うよりも無駄な手続きが増えてしまいます。
ただ、こちらも40dpがしっかり取得できるので、場合によっては役に立つかもしれません

株式会社ゆめみ

Discussion