🪟

iPadOS 26のウィンドウコントロールを考慮する

に公開

iPadOS 26から、ユーザーはアプリのウィンドウサイズを自由に変更することができるようになりました。
そして、ウィンドウをシームレスに閉じたり、最小化、サイズ変更、タイル表示したりすることができる「ウィンドウコントロール」が導入されました。

なお、フルスクリーン表示を強制する方法は、iPadOS 26.0でおそらく提供されていないようです。
そのため、すべてのアプリはコンテンツがウィンドウコントロールによって隠されないよう、レイアウトを考慮する必要があります。

ウィンドウコントロールの表示領域を取得し、レイアウトを調整する方法を見ていきましょう!

SwiftUIでウィンドウコントロールを考慮する

Toolbarを使う

Toolbarを使用している場合、ToolbarItem(placement:content:)が自動的にウィンドウコントロールを避けて配置されます。
そのため、特別な対応は不要です。

実装例

Text("↖︎左上に注目")
  .toolbar {
    ToolbarItem(placement: .topBarLeading) {
      Text("1")
    }

    ToolbarItem(placement: .topBarLeading) {
      Text("2")
    }

    ToolbarItem(placement: .topBarLeading) {
      Text("3")
    }

    ToolbarItem(placement: .topBarTrailing) {
      Image(systemName: "ellipsis")
    }
  }

カスタムUIでウィンドウコントロールを考慮する

ナビゲーションバーを自作している場合や、Toolbarを使用しない場合は、ウィンドウコントロールの表示領域を自前で考慮する必要があります。

iOS 26以降では、GeometryProxyに追加されたcontainerCornerInsetsプロパティから、ウィンドウコントロール領域のサイズ情報を取得できます。

これを可視化してみると次のようになります。

この値を使って、ビューがウィンドウコントロールと重ならないようにレイアウトを調整しましょう。
containerCornerInsetsの値をアニメーションにかけてあげると、フルスクリーン↔︎ウィンドウ表示の切り替わりが滑らかに見えて良いかもしれませんね。

GeometryReader { proxy in
  Text("ここに注目!")
    .padding(.leading, proxy.containerCornerInsets.topLeading.width)
    .animation(.default, value: proxy.containerCornerInsets)
}

UIKitでウィンドウコントロールを考慮する

iOS 26以降では、UIKitに次のAPIが追加されました。

@available(iOS 26.0, tvOS 26.0, *)
@available(watchOS, unavailable)
extension UIView {
    @MainActor @preconcurrency public func layoutGuide(for region: LayoutRegion) -> UILayoutGuide

    public struct LayoutRegion : Hashable, Equatable {
        public enum AdaptivityAxis : Equatable {
            case horizontal

            case vertical
        }

        public static func safeArea(cornerAdaptation: AdaptivityAxis? = nil) -> UIView.LayoutRegion

        public static func margins(cornerAdaptation: AdaptivityAxis? = nil) -> UIView.LayoutRegion

        public static func readableContent(cornerAdaptation: AdaptivityAxis? = nil) -> UIView.LayoutRegion
    }
}

従来のsafeAreaLayoutGuideと同様に、layoutGuide(for:)を利用することで、セーフエリアなどを考慮した制約を設定することができます。
さらに、cornerAdaptation引数を指定することで、ウィンドウコントロール領域も自動的に考慮されます。

実装例

NSLayoutConstraint.activate([
    uiView.topAnchor.constraint(equalTo: view.layoutGuide(for: .safeArea(cornerAdaptation: .vertical)).topAnchor),
    uiView.leadingAnchor.constraint(equalTo: view.layoutGuide(for: .safeArea(cornerAdaptation: .horizontal)).leadingAnchor),
    uiView.trailingAnchor.constraint(equalTo: view.layoutGuide(for: .safeArea(cornerAdaptation: .horizontal)).trailingAnchor),
    uiView.bottomAnchor.constraint(equalTo: view.layoutGuide(for: .safeArea(cornerAdaptation: .vertical)).bottomAnchor),
])

extension

ウィンドウコントロールを非表示にする

ホームインジケーター等を非表示にすることができるpersistentSystemOverlays(_:) Modifierは、ウィンドウコントロールも非表示にすることができます。
ただし見えなくなっているだけで存在はしています。タップ判定はあり、containerCornerInsetsの値もそのままです。
使用するとしても、本当に必要な時に一時的に非表示にする程度が良さそうです。

Liquid Glass無効化時

Xcode 26ではLiquid Glassを無効化するオプションが存在します。Info.plistに以下のKey-Valueを入力することで無効化することができますが、この場合、ウィンドウコントロールの表示領域の取得ができなくなります

Info.plist
	<key>UIDesignRequiresCompatibility</key>
	<true/>

代わりに、ウィンドウコントロールはセーフエリア外の領域に表示されるようになっているので、セーフエリアを考慮したレイアウト設計を行うことで、コンテンツとウィンドウコントロールが重ならないようにすることができます。

Liquid Glass有効化時 Liquid Glass無効化時

参考

https://developer.apple.com/jp/videos/play/wwdc2025/208/

Discussion