モーダルを下からせり上げる「シート」を、ちょうど良い高さで表示したい——そんな時に使うのが .presentationDetents
です。
SwiftUIの.sheet
に付けるだけで、ユーザーがシートの高さを段階的に切り替えられる「スナップ位置」を定義できます。
.presentationDetents
は検索フィルタや詳細ビュー、ミニプレイヤーなど、全画面は大げさだけど少しだけ見せたい場面に最適です。
.presentationDetentsとは?
.presentationDetents
は、シートの高さの候補を指定する修飾子です。
ユーザーはスワイプでその候補間をスナップ移動でき、アプリ側もバインディングで現在の高さを把握・変更できます。
主な特徴
.presentationDetents
の利点は、段階的に高さを制御できる点です。
下のポイントを押さえると設計の自由度が一気に上がります。
- 複数の高さ候補をセットで指定できる(例:
.medium
,.large
)
- 割合やピクセル高さで細かいカスタムが可能(
.fraction(_:)
,.height(_:)
) - 高さの現在値をバインディングで監視・変更できる(
selection:
) - ドラッグインジケータや背景、インタラクション抑止など周辺APIと併用しやすい
基本的な使い方
.presentationDetents
の使い方は下記の通りです。
1. 最小例:中間と最大を用意する
最もよく使う組み合わせが「.medium
と .large
」です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
struct ContentView: View { @State private var show = false var body: some View { Button("シートを開く") { show = true } .sheet(isPresented: $show) { SheetView() .presentationDetents([.medium, .large]) .presentationDragIndicator(.visible) } } } struct SheetView: View { var body: some View { VStack { Text("半分 or 全画面でスナップ") Spacer() } .padding() } } |
ポイント
・.presentationDetents([.medium, .large])
で高さの候補を宣言
・.presentationDragIndicator(.visible)
で上部の「つまみ」を明示
指定した割合でカスタム(fraction)表示
画面の高さに対する割合で細かく設計できます。
下記では最初、モーダルが全体の25%までで表示されます。
ただ、その位置で固定されるのではなく、ユーザー側で自由に画面の50%、全体のもー。
1 2 3 4 5 |
.sheet(isPresented: $show) { SheetView() .presentationDetents([.fraction(0.25), .fraction(0.5), .large]) } |
ポイント
0.0 ... 1.0
の範囲でモーダルを表示させる高さを指定できる(0.25=25%など)- 端末や回転に強く、レスポンシブな見え方にしやすい
ぴったり高さでカスタム(height)表示
コンテンツの実寸に合わせたい時はポイント値で。
1 2 3 4 5 |
.sheet(isPresented: $show) { SheetView() .presentationDetents([.height(240), .large]) } |
ポイント
- 画面の高さに合わせて、ぴったりの高さに指定することができる
- 最低/最大サイズや安全領域の都合で指定通りにならないこともあるのでよくテストする必要あり
現在のデテントを追跡・変更(selection)
プログラムから高さを変えたり、今どの高さかを知りたい時に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
struct ContentView: View { @State private var show = false @State private var detent: PresentationDetent = .medium var body: some View { Button("開く") { show = true } .sheet(isPresented: $show) { SheetView() .presentationDetents([.fraction(0.25), .medium, .large], selection: $detent) .onChange(of: detent) { print("現在の高さ:", detent) } } } } |
ポイント
selection
で現在のデテントを双方向バインド
- バインド値は必ず候補セットに含める必要がある(含まれないと反映されない)
端末で高さを切り替える(iPhone/iPad)
画面の大きさで割合を変えると自然なUIになります。
1 2 3 4 5 6 |
.sheet(isPresented: $show) { let isPad = UIDevice.current.userInterfaceIdiom == .pad SheetView() .presentationDetents([.fraction(isPad ? 0.25 : 0.2), .large]) } |
ポイント
UIDevice.current.userInterfaceIdiom == .pad
でiPadかiPhoneかを判定- iPadは表示領域が広いため、やや高めの割合が使いやすい
- Universal設計ではfractionベースが扱いやすい
一緒に覚えておきたい関連修飾子
.presentationDetents
と合わせて覚えておきたい関連する修飾子を紹介します。
下記の修飾子も覚えておくと、.sheet()でのモーダル表示の際に柔軟なUIにすることが可能になるはずです!
.presentationDragIndicator(_:)
シート上部のドラッグインジケータの表示制御(.visible
/ .hidden
/ .automatic
)。
操作可能性を明示でき、誤操作も減らせます。
.interactiveDismissDisabled(_:)
下スワイプでのクローズを抑止。
未保存データがあるフォーム等での誤閉じを防げます。
.presentationBackground(_:)
シートの背景をColor
やMaterial
で装飾。
アプリのブランディングに合わせた表現が可能。
.presentationBackgroundInteraction(_:)
背面コンテンツのタップ可否を制御(.enabled
/ .disabled
/ .upThrough(_)
)。
シート越しの操作を許すかどうかを場面に応じて切り替えられます。
注意点
.presentationDetents
は便利な一方で、いくつか注意点があります。
事前に下記の点を押さえておけば、想定外の挙動を避けられます。
iOS 16+ 前提
SwiftUIの.presentationDetents
はiOS 16以降にしか利用できません。
fraction/heightは制約の影響を受ける
コンテンツの最小サイズやセーフエリア、キーボード表示などで指定値が調整される。
特にheight
はその通りにならない場合があるので、よくテストをする必要があります。
selectionは候補に含める
バインディング側が候補外の値だと反映されない。
状態遷移時は必ず候補集合と同期する。
まとめ
.presentationDetents
は、シートの高さを段階的にコントロールできるものです。
関連する修飾子と一緒に覚えることでモーダル表示の時にUIのカスタマイズがかなりしやすくなるはずです!
参考リンク