UIの高さを固定するな

たとえばこういうUIを作ってというデザインの指示が来たときに…

![](https://storage.googleapis.com/zenn-user-upload/58c33251d4bc-20241223.png)

こういうコードを書いていませんか？

```kotlin
@Composable
fun ListItem(
    title: String,
    description: String,
    modifier: Modifier = Modifier,
) {
    Row(
        modifier = modifier.height(72.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Icon(...)
        Column(Modifier.weight(1f)) {
            Text(
                text = title,
                style = ...
            )
            Text(
                text = description,
                style = ...
            )
        }
        Button(...)
    }
}
```

注意していただきたいのは、 `modifier.height(72.dp)` の部分です。

**高さ72というデザイン指示なのだから、高さ72を指定するのは当然じゃないか** と思われるかもしれませんが、そうではないのです。高さを固定するこのような実装にはいくつか問題があります。

## 高さが固定されているとどうなるか

### `title`や`description`が長い場合

`title`や`description`がものすごく長い文字列だった時には、それぞれが2行、3行…と複数行になって表示される可能性があります。

`maxLines`を指定して行数の上限を設けることは可能ですが、表示されうる最小行数のパターンと最大行数のパターンで**両方とも高さが同じで大丈夫でしょうか？**

### 端末のフォントサイズを拡大している場合

全てのユーザーが端末のデフォルトのフォントサイズで使用しているとは限りません。中にはフォントサイズを拡大して使用しているユーザーもいます。

もし最大行数に制約を入れたとしても、**端末のフォントサイズを拡大していてもテキストは指定した高さに収まるでしょうか？**

### 右のボタンの幅が大きくなった場合

右側に配置されている「送信」と書かれたボタンの横幅は、「送信」という文字列の幅に合わせたデザインになっています。日本語だと全角二文字分の幅ですし英語でもSendなのでそんなに変わりません。ですが、たとえばロシア語では *отправлять* と書くので、**3倍くらいの横幅になります。**

ボタンの幅が広くなるということは、真ん中のテキストの表示領域もその分少なくなるということです。1行に収まると思っていた文字列が2行になるかもしれません。行数の制約を入れていたとしても、元々「2行表示すれば十分だろう」と思っていたものが、実際に使ってみたら「2行でも全然情報量が足りない…」となるかもしれません。

## それではどうするか？

デザイナーが高さを72と決めたのは、あくまで

- 当てはめるデータがこんな感じで
- 端末の標準フォントサイズを使用している時に
- 特定の言語で表示していたら

という前提条件のもとでの話です。 **前提条件が変われば、高さ72というのは適切な値ではなくなるはずです。**

したがって、エンジニアは**高さを固定しないレイアウトを実装するべきです。**

じゃあどういう実装にするか？というのはケースバイケースなので最終的にはデザイナーと協議して決めていただくのが良いのですが、大まかには以下のどちらかのパターンが考えられると思います。

### 高さについては一切制約を付けない

高さを固定するのではなく、内側のUIにパディングをつけることで目的の見た目を達成できるようにします。たとえば「`text`と`description`の上下のパディングを8にする」といった実装にします。

```kotlin
@Composable
fun ListItem(
    title: String,
    description: String,
    modifier: Modifier = Modifier,
) {
    Row(
        modifier = modifier, // ここでheightを固定するのではなく
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Icon(...)
        Column(Modifier.weight(1f).padding(vertical = 8.dp)) { // 上下のパディングで対応する
            Text(
                text = title,
                style = ...
            )
            Text(
                text = description,
                style = ...
            )
        }
        Button(...)
    }
}
```

この場合、文字列が長くなった際には`title`と`description`の上下パディングはそのままにUI全体が縦に大きくなります。

![](https://storage.googleapis.com/zenn-user-upload/3dcab69f54bb-20241223.png)

### 最小の高さのみ指定する

高さが72では収まらない場合に高さを増やすのは致し方ないが、その場合はできるだけ小さくしたいという場合は、パディングを付けるのではなく高さの指定に幅を持たせる方が良いかもしれません。

```kotlin
@Composable
fun ListItem(
    title: String,
    description: String,
    modifier: Modifier = Modifier,
) {
    Row(
        modifier = modifier.heightIn(min = 72.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Icon(...)
        Column(Modifier.weight(1f)) {
            Text(
                text = title,
                style = ...
            )
            Text(
                text = description,
                style = ...
            )
        }
        Button(...)
    }
}
```

![](https://storage.googleapis.com/zenn-user-upload/382b5e455b0e-20241223.png)

もちろん、パディングを付けるパターンと両方合わせるということもあるでしょう。

## おわりに

なるべくデザイナーの意図した表示を維持しつつ、**最適な表示を維持できない場合にもユーザビリティを損ねず、なるべくイイ感じの表示を保てるような実装をする** というのがエンジニアの腕の見せ所です。

- 「これって文字が長いときはどうなります？」
- 「端末のフォントサイズを拡大しているユーザーだとこのデザインだと収まらないと思います」
- 「◯◯語だとここのボタンは大きくなるのでレイアウトを見直した方が良いです」

など、様々な環境を想定してデザイナーにツッコミや改善の提案をしてあげるのはエンジニアの仕事です。

「上がってきたデザインに高さ◯◯と書いてあったから」と思って`Modifier.height(◯◯)`とコードを書く前に、一歩立ち止まって本当に必要な実装は何かを考えるようにしましょう。