SwiftUI の fixedSize で自然サイズを優先させる

SwiftUI のレイアウトシステムでは、親ビューが子ビューにサイズを提案し、子ビューはその提案に基づいて自身のサイズを決定します。fixedSize モディファイアはこの交渉プロセスに介入し、親の提案を無視して子ビューが本来持つ「理想サイズ」を優先させます。

テキストが切れる問題

fixedSize の必要性を理解するために、まずテキストが切り詰められるケースを見てみましょう。

HStack {
    Text("これは非常に長いテキストで、親のスペースに収まりきらない場合があります")
        .lineLimit(1)
    Text("右端")
}
.frame(width: 250)

HStack の幅が 250 に制限されているため、左側の Text は省略記号(…)で切り詰められます。通常はこの動作が望ましいですが、テキスト全体を表示したい場面もあるでしょう。

fixedSize で理想サイズを優先させる

fixedSize を付けると、ビューは親からのサイズ提案を無視して、自分のコンテンツに必要なサイズを確保します。

Text("これは非常に長いテキストで、親のスペースに収まりきらない場合があります")
    .fixedSize()

この Text は親が狭いスペースを提案しても、テキスト全体を表示するのに必要な幅を確保します。結果として親の領域をはみ出す可能性がありますが、テキストが切れることはなくなります。

水平・垂直を個別に制御する

fixedSize は水平方向と垂直方向を独立に制御できます。

Text("長いテキストが複数行にわたって表示されます。fixedSize で垂直方向の理想サイズを優先します。")
    .fixedSize(horizontal: false, vertical: true)
    .frame(width: 200)

horizontal: false で幅は親の提案に従い、vertical: true で高さは理想サイズ(全テキストを表示するのに必要な高さ)を優先します。つまり、幅は制限しつつ行数は切り詰めないという動作になります。

fixedSize(horizontal: true, vertical: false)

幅は理想サイズを優先し、高さは親の提案に従う。テキストを 1 行で全部表示したいときに使う

fixedSize(horizontal: false, vertical: true)

幅は親の提案に従い、高さは理想サイズを優先する。テキストの行数を制限せず全文を表示したいときに使う

HStack 内での fixedSize

複数のビューがスペースを奪い合う状況で、特定のビューだけにサイズ優先権を与えたいときにも fixedSize は役立ちます。

HStack {
    Text("ラベル")
        .fixedSize()
    
    Text("この部分は長いテキストですが、スペースに応じて折り返されます")
        .lineLimit(2)
}
.padding()

「ラベル」に fixedSize を付けることで、このテキストは絶対に省略されません。残りのスペースが右側の長いテキストに割り当てられ、そちらが折り返しや省略を受け持ちます。

複数ビューの高さを揃える

fixedSize の意外な活用法として、HStack 内の複数ビューの高さを揃えるパターンがあります。

HStack(alignment: .top) {
    Text("短い")
        .padding()
        .frame(maxWidth: .infinity)
        .background(Color.blue.opacity(0.2))
        .cornerRadius(8)
    
    Text("こちらは少し長いテキストで、複数行にわたります")
        .padding()
        .frame(maxWidth: .infinity)
        .background(Color.green.opacity(0.2))
        .cornerRadius(8)
}
.fixedSize(horizontal: false, vertical: true)

HStack に .fixedSize(horizontal: false, vertical: true) を付けると、HStack は子ビューの中で最も高いものに合わせた理想の高さを確保します。これにより、カード型 UI で高さが揃わない問題を解決できます。

fixedSize を使うときの注意点

fixedSize はビューを親の領域からはみ出させる可能性があるため、使いどころを選ぶ必要があります。ScrollView の中やリストのセル内など、はみ出しても問題ない文脈で使うのが安全です。固定レイアウトの画面で無闇に fixedSize を使うと、他のビューと重なってしまう恐れがあるので注意しましょう。