WWDC.ai

Prepare your app for iPhone Duo

Update iPhone apps for iPhone Duo's foldable displays with Xcode 27.1, adaptive layouts, size classes, safe areas, and reserved regions.

Watch on Apple Developer

TL;DR

  • Build with the iOS 27.1 SDK in Xcode 27.1 to opt into the full-screen iPhone Duo experience, including edge-to-edge inner display layout and vertical standard bars.
  • Test in the iPhone Duo simulator using DeviceHub controls for open, closed, rotated, and folded poses; also test Split View multitasking on the inner display.
  • Use size classes, trait collections, environments, and scene-local geometry instead of interface orientation, user interface idiom, or UIScreen.main assumptions.
  • Prefer standard navigation and presentation APIs, respect asymmetric safe areas and layout margins, and use ReservedRegion or UIViewReservedRegion for custom edge-to-edge UI.

Build and test with Xcode 27.1

Apps run on iPhone Duo even without rebuilding, but each newer SDK gives the app more usable display area. With the iOS 27 SDK, apps extend left of the status bar area on the inner display. With the iOS 27.1 SDK, apps can extend to the screen edge, and standard navigation and toolbar buttons can lay out vertically under the status bar.

Use Xcode 27.1 and the iPhone Duo simulator in DeviceHub to inspect every pose. The simulator controls let you open, close, rotate, and fold the device, which is essential because layout issues often appear only in a particular pose or display.

  • Download Xcode 27.1 to build with the iOS 27.1 SDK.
  • Run on the iPhone Duo simulator in DeviceHub.
  • Check opened, closed, rotated, folded, and inner-display Split View configurations.

Design for adaptive resizing, not device assumptions

iPhone Duo extends the same adaptive layout requirements that iPhone apps already face across different screen sizes, screen shapes, Dynamic Island regions, iPhone Mirroring on Mac, and resizable environments. Treat the app as resizing across a continuum rather than targeting one fixed phone shape.

Avoid using user interface idiom, fixed display dimensions, or interface orientation as layout proxies. The inner display does not honor supported interface orientations for layout in the same way as the outer display, so size classes are the recommended signal for choosing compact or expanded layouts.

  • Outer display behaves like other iPhones: portrait is compact width and regular height; landscape is compact width and compact height.
  • Inner display has regular horizontal and vertical size classes, making sidebars and denser layouts appropriate.
  • Support landscape where it makes sense, especially for tent-like folded use, but do not use orientation checks for layout decisions.

Read size classes

Use SwiftUI environment values or UIKit trait collections to choose layouts based on available space.

// SwiftUI
@Environment(\.horizontalSizeClass)
private var horizontalSizeClass

@Environment(\.verticalSizeClass)
private var verticalSizeClass

// UIKit
traitCollection.horizontalSizeClass
traitCollection.verticalSizeClass

Avoid global screen references

On a device with two displays, the main screen is ambiguous and is planned for future deprecation. Prefer local context: SwiftUI environment values, UIKit trait collections, the scene's bounds, or the screen associated with the current window scene.

For shapes that need to match hardware corners, use the Concentricity APIs introduced in iOS 26, which are updated for iPhone Duo screen shapes.

  • Do not rely on UIScreen.main for scale, bounds, or display selection.
  • If a screen is truly needed, access it from the current UIWindowScene.
  • Use traitCollection.displayScale instead of UIScreen.main.scale when rendering view-specific assets such as thumbnails.

Access the screen from the window scene

Derive the display from the scene that owns the window rather than a process-wide main screen.

// Avoid referencing the main screen on a two-display device.
// Access the screen dynamically from the window scene instead.
let screen = window?.windowScene?.screen

Replace main screen references

Use the current trait collection for display scale when rendering UI-dependent output.

func updateThumbnail(from image: UIImage) {
    // Before
    let screenScale = UIScreen.main.scale

    // After
    let screenScale = traitCollection.displayScale
    // ...
}

Use standard navigation and presentations

Standard navigation APIs automatically adapt to iPhone Duo poses. NavigationSplitView and UISplitViewController collapse to single-stack navigation when closed and can appear as tiled columns or overlays when open. TabView and UITabBarController adapt across inner and outer displays, including vertical tab layouts where appropriate.

The inner display can use sidebar-style tab navigation for richer layouts. Standard sheets, popovers, context menus, and alerts also adapt to each pose, including centered sheets on the inner display and vertically arranged buttons where needed.

  • Prefer NavigationSplitView or UISplitViewController for multi-column navigation.
  • Prefer TabView or UITabBarController for tab navigation that can adapt between compact, vertical, and sidebar placements.
  • Use standard presentation APIs when possible instead of hand-rolled modal geometry.

Show a sidebar on the inner display

Opt into sidebar placement for tab navigation on the larger inner display.

// SwiftUI
TabView { ... }
    .defaultTabBarPlacement(.sidebar)

// UIKit
tabBarController.sidebar.preferredPlacement = .sidebar

Respect safe areas, margins, and reserved regions

Navigation bars, toolbars, and tab bars lay out outside the safe area and automatically avoid system UI such as the status bar and hardware features such as the camera. Foreground and interactive content should remain inside the safe area; background artwork can extend behind bars and sidebars.

Safe areas and layout margins are often asymmetric on iPhone Duo, especially with vertical buttons in landscape or Split View multitasking. Handle each inset independently and test configurations where vertical content appears on either side of the app.

For custom bars or edge-to-edge UI, iOS 27.1 adds ReservedRegion in SwiftUI and UIViewReservedRegion in UIKit. These APIs let custom UI claim screen space outside the safe area while avoiding collisions with system-provided UI.

  • Use standard bars when possible because they automatically adapt to safe areas.
  • Constrain visible and interactive foreground content to the safe area.
  • Let noninteractive background content fill the full bounds when appropriate.
  • Do not compute width by assuming left and right safe area insets are equal.
  • Consider ReservedRegion or UIViewReservedRegion for complex custom layouts.

Handle foreground and background content

Keep controls reachable while allowing full-bleed backgrounds to extend behind system-adjacent regions.

// UIKit: align foreground content to the safe area
foreground.frame = view.bounds.inset(by: view.safeAreaInsets)

// SwiftUI: let background content extend past the safe area
.ignoresSafeArea()

// UIKit: let background content fill the available bounds
backgroundView.frame = view.bounds

Handle asymmetric safe area insets

Use all safe area inset values rather than mirroring one side onto the other.

// Avoid assuming insets on opposite sides are equal
let width = view.bounds.width - view.safeAreaInsets.left * 2

// Handle each side independently
let width = view.bounds.inset(by: view.safeAreaInsets).width
Unofficial, not associated with Apple. Made with ❤️ by

On this page

Ask AI