開発者向け
iPhone Duo のシート表示:配置と角丸の対応方法
iPhone Duo でのシート表示の仕組みを解説。presentationPlacement で leading・trailing・center を選ぶ方法と、concentricCornerRadii で角丸を揃える方法を紹介します。
AppleDuo 編集部公開 15分で読めます
このページの内容
通常の iPhone では、シートは下からスライドして画面幅いっぱいに表示されます。iPhone Duo ではシート表示の仕組みが異なります。大きな内側ディスプレイでは、シートが中央に浮かんだり leading 端や trailing 端に寄せて表示されたりし、その輪郭は画面の不均一な角に沿ってカーブします。このガイドでは、シートの表示位置を制御する iOS 27 の API、各姿勢でのシステムの扱い、そして独自の角丸シェイプをハードウェアに揃える方法を解説します。
ここでの内容はすべて、Apple のドキュメント、iPhone Duo の Tech Talk、デベロッパフォーラムでの Apple エンジニアの回答、そして iOS デベロッパ @sarunw の投稿に基づいています。AppleDuo チームはこのコードを実機で動かしていません。これらの API は iOS 27 と Xcode 27 で提供されたもので、リリース間で詳細が変わる可能性があります。
iPhone Duo でシートはデフォルトでどこに表示される?
シートはどの姿勢にも自動で適応します。Tech Talk「Prepare your app for iPhone Duo」で Apple は、外側ディスプレイのシートはバーボタンを縦に並べられること、内側ディスプレイのシートは中央に表示されることを説明しています。ポップオーバー、コンテキストメニュー、アラートも同様に適応します。
Apple の DTS エンジニアはデベロッパフォーラムのスレッドでさらに詳しく説明しています。デバイスを折り曲げているときはすべてのシートが leading 端に移動し、内側ディスプレイを平らに開いたときは中央に表示されます。
シート内のバーには独自のルールがあります。Apple の記事「Preparing your app for iPhone Duo」によると、外側ディスプレイではシートのバーがデフォルトで縦向きに表示されます。内側ディスプレイでは、中央または leading のシートではツールバーが横向き、trailing のシートでは縦向きになります。
| 場所 | デフォルトのシート位置 | シート内のバー |
|---|---|---|
| 外側ディスプレイ(閉じた状態) | 自動で適応 | デフォルトで縦向き |
| 内側ディスプレイ、半分折り曲げ | leading 端(Apple DTS による) | leading 配置では横向き |
| 内側ディスプレイ、平らに開いた状態 | 中央 | 中央配置では横向き |
| 内側ディスプレイ、trailing 配置 | trailing 端(指定した場合) | 縦向き |
シート内で縦向きのバーを使いたくない場合は、SwiftUI では toolbarVerticalBehavior(_:)、UIKit では preferredVerticalBarBehavior でオプトアウトできます。これらのバーの構成やアイテムのオーバーフローについては、iPhone Duo の縦向きツールバーのガイドで解説しています。
SwiftUI で presentationPlacement を使うには?
iOS 27 では presentationPlacement(_:) モディファイアと PresentationPlacement 型が追加されました。presentationDetents などのモディファイアと並べて、シートのコンテンツに適用します。次は Apple のドキュメントにある例で、シートの背後にある地図をより多く見せられます。
Map()
.sheet(isPresented: $isPresented) {
PlaceDetailView()
.presentationDetents([.medium, .large])
.presentationPlacement(.leading)
}
PresentationPlacement には 4 つの static 値があります。Apple によると、これを反映するのはシート表示だけで、ポップオーバー、アラート、メニューはこのモディファイアを無視します。
| 値 | Apple のドキュメントの説明 |
|---|---|
.automatic | システムが配置を決定する(デフォルト) |
.center | 表示元のビュー内で中央に配置する |
.leading | 表示元のビューの leading 端に配置する |
.trailing | 表示元のビューの trailing 端に配置する |
leading と trailing はレイアウト方向に基づく用語なので、右から左に書く言語では .leading によってシートは右側に配置されるはずです。これは縦向きバーとは異なります。@sarunw が指摘しているように、縦向きバーは読む方向ではなくハードウェアに従います。アプリをアラビア語やヘブライ語にローカライズしている場合は、両方の方向でテストしてください。
UIKit の場合は?
UIKit では、表示するビューコントローラの UISheetPresentationController で preferredPlacement プロパティを設定します。Apple の記事ではこれが presentationPlacement(_:) に対応する UIKit の API として挙げられており、Apple の Technology Evangelist もこのフォーラムスレッドで、ユーザーの iPhone Duo の持ち方にシートをどう適応させるかを調整する方法としてこれを示しています。コードを書く前に、Xcode 27 の UIKit ヘッダで正確な値の名前を確認してください。
どのシート配置を選ぶべき?
まずは .automatic から始めましょう。システムはデバイスの折り曲げに合わせてシートを中央と leading 端の間で移動させ、それぞれに適したバーの向きを選びます。配置を上書きするのは、理由があるときだけにしてください。
片側に寄せる妥当な理由には次のようなものがあります。
- 主要なコンテンツを見えるままにする。 Apple 自身の例では、地図の上に表示する場所カードに
.leadingを使っています。同じ考え方は、写真、ドキュメント、ゲーム盤の横に置くインスペクタ風のシートにも使えます。 - シートを縦向きバーから離す。 内側ディスプレイでは、姿勢によってバーが一方の端に沿って配置されます。メインのビューがすでにその端を使っているなら、反対側にシートを置けばツールバーが隠れません。trailing のシートには独自の縦向きツールバーが付くことも覚えておいてください。
- シートが編集するコンテンツの横に置く。 変更対象の段落の横に書式設定シートがあるほうが、段落を覆ってしまうシートより使いやすくなります。
サインイン、共有フロー、設定フォームのように、シートの背後に重要なものがない独立した作業には .center を選びます。
姿勢に合わせて配置を変えられる?
自動では変わりません。Apple のエンジニアはフォーラムで、指定した配置は折り曲げ時だけでなく常に適用され、「center、次に trailing」のようなフォールバック順序は存在しないと認めています。推奨される回避策は、アクティブな division の予約領域を検出して自分で配置を選ぶことです。
struct PlaceMapView: View {
@State private var isPresented = true
var body: some View {
GeometryReader { proxy in
// アクティブな division = 折り目が使われている(半分折り曲げ)
let isFolded = !proxy.reservedRegions(kind: .division).isEmpty
Map()
.sheet(isPresented: $isPresented) {
PlaceDetailView()
.presentationDetents([.medium, .large])
.presentationPlacement(isFolded ? .trailing : .automatic)
}
}
}
}
これはドキュメント化された 2 つの API、reservedRegions(kind:) と presentationPlacement(_:) を組み合わせたスケッチで、Apple が公開したコードではありません。アクティブな領域と非アクティブな領域については予約領域と折り目のガイドで詳しく説明しており、姿勢の変化を直接監視する方法はヒンジの状態と onHingeChange で扱っています。
iPhone Duo でシートが角に沿ってカーブするのはなぜ?
@sarunw が指摘しているように、iPhone Duo のシートはデバイスの不均一な角に沿ってカーブします。システムのシート、ポップオーバー、その他のコンテナは同心の角(concentric corners)を使っています。内側の各カーブが外側のカーブと中心点を共有するため、両者の間隔が全周にわたって均一に保たれます。
Apple は Tech Talk で、iOS 26 で導入された Concentricity API が iPhone Duo の画面形状に対応するよう更新されたと説明しています。SwiftUI では ConcentricRectangle、UIKit では UICornerConfiguration がそれにあたります。Tech Talk の SwiftUI サンプルは、塗りつぶした 1 つのシェイプです。
ConcentricRectangle()
.fill(Color.green)
.padding(8.0)
.ignoresSafeArea()
システムのシートとこれらのシェイプを使えば、何もしなくても角が揃います。問題になるのは、別の iPhone 向けに調整したハードコードの cornerRadius で独自のパネルを描画している場合です。
concentricCornerRadii で画面の角に合わせるには?
iOS 27 では GeometryProxy に concentricCornerRadii が追加されました。ConcentricRectangle と違って何も描画せず、カスタム描画、アニメーション、独自のシェイプに使える RectangleCornerRadii? を返します。関連メソッドの concentricCornerRadii(in:) は、ビュー内の部分矩形に対して同じことを行います。
Apple のドキュメントにはルールが示されています。各角の半径は、コンテナの角の半径から、ビューの角とコンテナの角との距離を引いた値です。コンテナの角から遠い角は 0 になり、結果はビューが持てる最大の半径に制限されます。
@sarunw は計算例を示しています。iPhone 18 Pro では画面の角が 62 ポイントなので、そこから 16 ポイント離れたビューは 62 − 16 = 46 ポイントになります。この 62 ポイントという数値は彼の投稿によるもので、私たちが確認したページでは Apple はデバイスごとの角の半径を公開していません。
| 画面の角 | 角からのインセット | 同心の半径 |
|---|---|---|
| 62 pt(iPhone 18 Pro、@sarunw による) | 16 pt | 46 pt |
| 62 pt | 8 pt | 54 pt |
| 62 pt | 62 pt 以上 | 0 pt |
下の 2 行は、同じ角にドキュメントの計算式を当てはめたもので、個別に測定した値ではありません。iPhone Duo では角が均一ではないため、ハードコードするより値を読み取るほうが確実です。
このプロパティは、コンテナシェイプが設定されていない場合や、シェイプが十分な角の情報を提供しない場合に nil を返します。Apple のサンプルでは containerShape(_:) で明示的に設定しています。nil には必ず適切なフォールバックを用意してください。
struct FloatingPanel: View {
private let fallback = RectangleCornerRadii(
topLeading: 16, bottomLeading: 16,
bottomTrailing: 16, topTrailing: 16
)
var body: some View {
GeometryReader { proxy in
UnevenRoundedRectangle(
cornerRadii: proxy.concentricCornerRadii ?? fallback,
style: .continuous
)
.fill(.thinMaterial)
}
.padding(16)
.ignoresSafeArea()
}
}
このパネルは端から 16 ポイント内側に配置され、プロキシから同心の半径を取得して UnevenRoundedRectangle で描画します。システムがコンテナシェイプを解決できない場合、パネルは均一な 16 ポイントの半径にフォールバックします。
UnevenRoundedRectangle はいつ使う?
UnevenRoundedRectangle は、角ごとに異なる半径の矩形を描画します。iOS 27 の新機能ではありませんが(Apple のドキュメントでは iOS 16 から利用可能)、concentricCornerRadii とは自然に組み合わせられます。画面の一方の角に近いビューは、その角では大きな半径、それ以外では小さな半径が必要になるからです。
上の例のように RectangleCornerRadii 値を渡すことも、角ごとに指定することもできます。
UnevenRoundedRectangle(
topLeadingRadius: 46,
bottomLeadingRadius: 46,
bottomTrailingRadius: 12,
topTrailingRadius: 12,
style: .continuous
)
.fill(.background.secondary)
このシェイプは leading 端に固定したカスタムパネルに適しています。外側の 2 つの角は画面に沿い、内側の 2 つの角は小さく保たれます。46 のような固定値は 1 つのデバイスと 1 つのインセットでしか成り立たないため、concentricCornerRadii で計算した値を優先してください。
| 用途 | 使うもの | 対応バージョン |
|---|---|---|
| コンテナに合ったシェイプをシステムに描画させる | ConcentricRectangle | iOS 26 |
| カスタム描画用に半径だけを取得する | GeometryProxy.concentricCornerRadii | iOS 27 |
| 角ごとに独自の半径を指定する | UnevenRoundedRectangle | iOS 16(Apple のドキュメントによる) |
iPhone Duo のシートでよくある落とし穴は?
- あらゆる場所で配置を上書きする。 固定した配置はすべての姿勢に適用されるため、半分折り曲げた状態で適切に見えるシートが、平らに開いた状態では不自然に見えることがあります。特定の画面で必要な場合を除き、
.automaticを使いましょう。 - カスタムのプレゼンテーションコントローラ。 独自に構築したプレゼンテーションには、システムによる姿勢への適応や同心の角が適用されません。detent 付きのシステムシートを優先してください。
- ハードコードした角の半径。 古い iPhone からコピーした半径は iPhone Duo の角に合いません。
concentricCornerRadiiを読み取るか、ConcentricRectangleを使いましょう。 - シート内の不均一な余白。 縦向きバーの横では、辺ごとに余白が異なります。
contentMargins(for:edges:)についてはセーフエリアとコンテンツマージンの記事で解説しています。 - ベータ版のツールチェーン。 あるデベロッパは、Xcode 27 beta 6 を使った実機で、可用性チェックを入れていても起動時にクラッシュした(
PresentationPlacement.leadingの「Symbol not found」)と報告しています。このスレッドでは原因は確認されていません。自分のバグとしてデバッグする前に、正式版の Xcode 27 と対応する OS でビルドしてください。
すべてのシートを、閉じた状態、半分折り曲げた状態、平らに開いた状態のすべての姿勢で、両方の向きについて確認してください。そのほかに実施すべき確認項目は iPhone Duo 対応チェックリストにまとめています。
まとめ
- iPhone Duo では、シートはデフォルトで適応します。開いた内側ディスプレイでは中央に、折り曲げると leading 端に移動し、外側ディスプレイではバーが縦向きになります。
- いずれも iOS 27 の新 API である
presentationPlacement(_:)(SwiftUI)とpreferredPlacement(UIKit)で、leading、trailing、center のシートを指定できます。これを反映するのはシートだけで、すべての姿勢に適用されます。 - 姿勢に応じて配置を変えるには、
reservedRegions(kind:)でアクティブな division を確認し、自分で値を選びます。 GeometryProxyのconcentricCornerRadii(iOS 27)は、コンテナの角と中心を共有する半径を返します。nilの処理を忘れずに。- その半径は
UnevenRoundedRectangleで描画するか、シェイプだけが必要ならConcentricRectangleを使います。
次はバーが縦向きの端に移動する仕組みを読み、折りたたみ向けに作られたゲームのコレクションでデベロッパが何を作ったかをご覧ください。
よくある質問
iPhone Duo でシートを leading 側や trailing 側に表示するには?
SwiftUI では、シートのコンテンツに presentationPlacement(.leading) または presentationPlacement(.trailing) を適用します。UIKit では、ビューコントローラの UISheetPresentationController の preferredPlacement プロパティを設定します。この配置指定が反映されるのはシート表示だけです。
iPhone Duo ではシートはデフォルトでどこに表示されますか?
automatic の配置ではシステムが位置を決めます。Apple はシートが内側ディスプレイの中央に表示されると説明しており、デベロッパフォーラムでは Apple のエンジニアが、デバイスを折り曲げているときはシートが leading 端に移動し、内側ディスプレイを平らに開いたときは中央に表示されると回答しています。
デバイスを折り曲げると presentationPlacement は変わりますか?
変わりません。デベロッパフォーラムでの Apple エンジニアの回答によると、指定した配置は折り曲げ時だけでなく常に適用されます。姿勢ごとに変えたい場合は、アクティブな division の予約領域があるかを確認し、自分で配置を選んでください。
concentricCornerRadii は何を返しますか?
ビューの角がコンテナの角と中心を共有するために必要な角の半径を、RectangleCornerRadii 値として返します。コンテナシェイプが設定されていない場合や、シェイプが十分な角の情報を提供しない場合は nil を返します。iOS 27 の新 API です。
UnevenRoundedRectangle と ConcentricRectangle の違いは?
UnevenRoundedRectangle は、角ごとに指定した半径で矩形を描画します。iOS 26 で導入された ConcentricRectangle は、同心の角を自動で計算してシェイプを描画します。concentricCornerRadii はその中間で、半径だけを返すため、その値を UnevenRoundedRectangle や Path に渡して使えます。
出典
- presentationPlacement(_:) · Apple Developer Documentation
- PresentationPlacement · Apple Developer Documentation
- Preparing your app for iPhone Duo · Apple Developer Documentation
- Prepare your app for iPhone Duo (Tech Talk) · Apple Developer
- concentricCornerRadii · Apple Developer Documentation
- UnevenRoundedRectangle · Apple Developer Documentation
- Modal on trailing (DTS answer on sheet placement) · Apple Developer Forums
- Controlling sheet presentation across iPhone Duo poses · Apple Developer Forums
- A sheet can sit on the leading side, the trailing side, or the center · @sarunw on X
- The sheet on iPhone Duo curves around the device's uneven corners · @sarunw on X
- iOS 27 adds concentricCornerRadii to GeometryProxy · @sarunw on X
- 62 − 16 = 46: how a concentric corner is calculated · @sarunw on X
- Need a different radius on each corner? Use UnevenRoundedRectangle · @sarunw on X
- The vertical bar follows the hardware, not the reading direction · @sarunw on X
- .presentationPlacement(.leading) does not work! · Apple Developer Forums
折りたたみを、アプリの一部に。
AppleDuo は iPhone Duo を本当に活かしたアプリとゲームを紹介しています。App Store へのリンクを添えて送ってください。ほかの開発者の作品も見られます。