6
6

More than 1 year has passed since last update.

Jetpack Composeでコンテンツのサイズに柔軟に対応しつつ正方形を維持するレイアウト

Posted at

ここでは正方形を維持しつつコンテンツサイズに対して柔軟にレイアウトしたい時の実装の紹介です。

実装

以下のような Modifier#layout で縦横どちらか大きい方をサイズにするといったカスタムレイアウトで実現します。

Modifier.layout { measurable, constraints ->
    val placeable = measurable.measure(constraints)
    val width = placeable.width
    val height = placeable.height
    val size = maxOf(width, height)
    layout(size, size) {
        val x = (size - placeable.width) / 2
        val y = (size - placeable.height) / 2
        placeable.placeRelative(x, y)
    }
}

上記のコードを適用しているとコンテンツ側にテキストがある場合に、フォントサイズが変更された場合にも正方形を維持したまま拡大してくれます。

意図した挙動にならない実装パターン

Modifier#size、 Modifier#sizeIn

単純な Modifier#size の場合だとコンテンツ側のサイズが変わると追従できないため、テキストを含んでいてフォントサイズが変更され収まらない場合にテキストが切れてしまいます。
例えばコンテンツがアイコンだけといった、コンテンツ側にテキストのような可変となるようなものが含まれない場合だとこの実装で十分です。

Modifier#sizeIn の場合はコンテンツのサイズ変更に強くはできますが、正方形が維持できなくなります。

Modifier#aspect

Modifier#aspect は使う上で少しだけ条件があって KDoc に以下のような説明が書かれています。

Attempts to size the content to match a specified aspect ratio by trying to match one of the incoming constraints in the following order: Constraints.maxWidth, Constraints.maxHeight, Constraints.minWidth, Constraints.minHeight if matchHeightConstraintsFirst is false (which is the default), or Constraints.maxHeight, Constraints.maxWidth, Constraints.minHeight, Constraints.minWidth if matchHeightConstraintsFirst is true. The size in the other dimension is determined by the aspect ratio. The combinations will be tried in this order until one non-empty is found to satisfy the constraints. If no valid size is obtained this way, it means that there is no non-empty size satisfying both the constraints and the aspect ratio, so the constraints will not be respected and the content will be sized such that the Constraints.maxWidth or Constraints.maxHeight is matched (depending on matchHeightConstraintsFirst).

コンテンツが取りうるサイズが確定している縦か横のサイズに対してアスペクトを指定するようになっています。

そのため、例えばサイズを指定せずに Modifier.aspect(1f) とすると親の Composable fun を辿って確定するサイズに対して比率を指定するため、親にサイズ指定がないと以下のように画面全体のサイズを取ってしまいます。コンテンツサイズに対する比率の適用にはなりません。

Modifier.width(n.dp).aspect(1f) とすると設定した横幅に対して 1:1 の比率を適用しますが、実質 Modifier.size(n.dp) と同じなので、コンテンツが可変の場合に切れる問題が出てきます。

コンテンツのサイズが可変で正方形を維持したい、という場合は既存の Modifier の組み合わせでは難しい場合もあり、そういったときはカスタムレイアウトが一番調整しやすいです。

6
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
6
6