SwiftUI の frame モディファイアでサイズを指定する

SwiftUI では、ビューのサイズは親から提案されたサイズ(proposed size)と子が返す理想サイズ(ideal size)のやりとりで決まります。frame モディファイアはこの仕組みに介入し、ビューの幅・高さを明示的に制御するための手段です。

固定サイズの frame

最もシンプルな使い方は、幅と高さを直接指定する方法です。

Text("Hello")
    .frame(width: 200, height: 100)
    .background(Color.blue.opacity(0.2))

width と height を指定すると、Text は 200×100 のスペース内に配置されます。ここで重要なのは、frame は「枠を設定する」モディファイアであり、中のテキスト自体のサイズを引き伸ばすわけではないという点です。テキストは枠の中で alignment に従って配置されます。

alignment パラメータ

frame 内でのビューの配置位置は alignment で制御します。

Text("左上")
    .frame(width: 200, height: 100, alignment: .topLeading)
    .background(Color.green.opacity(0.2))

デフォルトは .center です。.topLeading.bottomTrailing など 9 方向の配置が可能で、ビューが frame より小さい場合に効果を発揮します。

最小・理想・最大サイズの指定

frame には柔軟なサイズ指定の形式もあります。minWidth、idealWidth、maxWidth、そしてそれぞれの高さ版を指定できるバリエーションです。

Text("可変幅のテキスト")
    .frame(
        minWidth: 100,
        maxWidth: .infinity,
        minHeight: 44
    )
    .background(Color.orange.opacity(0.2))

maxWidth: .infinity を指定すると、親が提案する幅いっぱいまで広がります。ボタンやバナーを画面幅に合わせたいときの定番パターンです。

固定 frame

width / height に具体的な値を指定する。サイズが確定するため予測しやすいが、画面サイズの変化に対応しにくい

柔軟な frame

min / ideal / max を組み合わせる。親のサイズ提案に応じて伸縮し、レスポンシブなレイアウトを作りやすい

.infinity の活用

.infinity は「可能な限り大きく」という意味を持ちます。幅と高さの両方に指定すると、ビューが親の領域全体を埋めるようになります。

Color.blue
    .frame(maxWidth: .infinity, maxHeight: .infinity)
    .ignoresSafeArea()

背景色を画面全体に敷きたいときなどに便利です。ただし .infinity は「他のビューを押しのけて際限なく大きくなる」わけではありません。あくまで親から提案された最大サイズまで広がるという動作になります。

frame の適用順序に注意する

frame はモディファイアなので、適用順序によって結果が変わります。padding と frame の順番を入れ替えた 2 つの例を比較してみましょう。

// パターンA: padding → frame
Text("Hello")
    .padding()
    .frame(width: 200, height: 80)
    .background(Color.red.opacity(0.2))

// パターンB: frame → padding
Text("Hello")
    .frame(width: 200, height: 80)
    .padding()
    .background(Color.red.opacity(0.2))

パターン A では、まず padding が付いたビューに対して 200×80 の frame が適用されます。パターン B では、200×80 の frame に対して外側に padding が追加されるため、最終的なサイズが大きくなります。SwiftUI のモディファイアは「外側にラップする」という考え方を持つと理解しやすいでしょう。

idealWidth / idealHeight と fixedSize の関係

idealWidth と idealHeight は、ビューが「理想とするサイズ」を宣言するものです。ただし、通常はこの値が直接使われることはなく、.fixedSize() モディファイアと組み合わせたときに効果を発揮します。

Text("非常に長いテキストがここに入ります")
    .frame(idealWidth: 300)
    .fixedSize(horizontal: true, vertical: false)

fixedSize を付けると、親からのサイズ提案を無視して理想サイズを優先するようになります。この仕組みについては別の記事で詳しく扱います。