-
Strike a pose with adaptive layouts on iPhone Duo
Learn how to create responsive, flexible layouts that work great on iPhone Duo. Explore displacement design patterns that keep content visible and reachable as people open and close their iPhone Duo. Discover how to use arrangement views in SwiftUI and UIKit to build split and overlay presentations, and find out how to query reserved regions to tailor layouts around the hinge and cameras.
Chapitres
- 0:00 - Introduction
- 0:27 - Reserved regions on iPhone Duo
- 1:29 - Designing around the hinge
- 2:26 - Displacement patterns
- 4:00 - Choose where content moves
- 5:12 - Adapt content to its new region
- 6:39 - Query reserved regions
- 7:50 - Division and occlusion regions
- 8:39 - System containers that adapt
- 9:20 - Introducing arrangements
- 11:17 - Build with ArrangementView
- 12:00 - Configure the split arrangement
- 13:21 - Use the overlay arrangement
- 14:39 - Choose between arrangements
- 16:09 - When not to use an arrangement
- 16:34 - Next steps
Ressources
Vidéos connexes
Tech Talks
-
Rechercher dans cette vidéo…
-
-
6:46 - Query reserved regions in SwiftUI
// SwiftUI GeometryReader { proxy in let regions = proxy.reservedRegions( kind: .division) } -
7:03 - Query reserved regions in UIKit
// UIKit let regions = view.reservedRegions( kind: .division) // Query the frame to incorporate it into your own layout let frames = regions.map(\.frame) -
7:22 - Include inactive regions
// SwiftUI GeometryReader { proxy in let regions = proxy.reservedRegions( kind: .division, options: .includeInactive) let frames = regions.map(\.frame) // ... } -
8:07 - Query occlusion regions
// SwiftUI GeometryReader { proxy in let regions = proxy.reservedRegions( kind: .occlusion) let frames = regions.map(\.frame) // ... } -
11:23 - Add an ArrangementView
// SwiftUI var body: some View { NavigationStack { ArrangementView { PlayerView() } secondary: { UpNextView() } } } -
11:26 - Add a UIArrangementViewController
// UIKit let arrangementVC = UIArrangementViewController() let navController = UINavigationController(rootViewController: arrangementVC) let playerVC = PlayerViewController() arrangementVC.setViewController(playerVC, for: .primary) let upNextVC = UpNextViewController() arrangementVC.setViewController(upNextVC, for: .secondary) -
12:00 - Specify the split arrangement style
// SwiftUI var body: some View { NavigationStack { ArrangementView { PlayerView() } secondary: { UpNextView() } .arrangementViewStyle(.split) } } -
12:41 - Restrict the split to one axis
// SwiftUI var body: some View { NavigationStack { ArrangementView { PlayerView() } secondary: { UpNextView() } .arrangementViewStyle( .split.axes(.horizontal)) } } -
13:07 - Update the arrangement in UIKit
// UIKit let arrangementVC = UIArrangementViewController() // ... arrangementVC.updateArrangement(.split.axes(.horizontal)) -
13:26 - Switch to the overlay arrangement
// SwiftUI var body: some View { NavigationStack { ArrangementView { UpNextView() } secondary: { PlayerView() } .arrangementViewStyle(.overlay) } } -
14:07 - Respond to the overlay Z index
// SwiftUI enum UpNextMinimization { case collapsed; case expanded } struct UpNextView: View { @Environment(\.overlayArrangementZIndex) private var zIndex: Int var body: some View { UpNextList(minimization: minimization) } var minimization: UpNextMinimization { zIndex > 0 ? .collapsed : .expanded } } -
14:21 - Read the Z index in UIKit
// UIKit let arrangementVC = UIArrangementViewController() // ... let primaryState = arrangementVC.state(for: .primary) myModel.minimization = (primaryState?.zIndex ?? 0) > 0 ? .collapsed : .expanded
-
-
- 0:00 - Introduction
Maria, a Human Interface Designer on Apple's design system, and Harry, a UI Frameworks engineer, introduce how to create layouts that adapt to the unique characteristics of iPhone Duo.
- 0:27 - Reserved regions on iPhone Duo
iPhone Duo has multiple displays, each with its own size class, plus hardware features that shape the available space — the hinge and the cameras on the outer and inner displays. These are called reserved regions, and you treat them like any other area your layout adapts to, such as window controls on iPadOS.
- 1:29 - Designing around the hinge
When the device is partially folded like a book, the hinge divides the inner display into multiple usable regions as the display curves through the center. Just as a photo spread across a book's spine stops reading as one continuous image, content and controls that span the fold become harder to see.
- 2:26 - Displacement patterns
Many interfaces flow naturally around reserved regions, while others benefit from displacement — adjusting the frame of existing elements based on available space. Displacement can scope from a single button to an entire container. Move elements independently when they can adapt alone, together when they work as a unit, and avoid excessive movement that weakens visual relationships. Continuously scrolling content like articles and feeds shouldn't displace.
- 4:00 - Choose where content moves
Let purpose guide where content moves, and note that the right destination changes with how the device is used. Partially folded like a book, alerts move to the trailing side, closer to where they'll appear as the device closes. Propped on a table, the top region suits content viewed at a distance while the bottom suits interactive controls. When multiple regions work, keep things contextual.
- 5:12 - Adapt content to its new region
Position and size change most often, but other visual properties adapt too. The system automatically repositions action sheets, alerts, menus, and popovers around reserved regions to keep them fully visible. In a split view like Reminders it keeps both columns visible with an even split, and a grid can preserve outer margins while increasing spacing around the hinge. Throughout, you're moving, resizing, or reorganizing what's already there.
- 6:39 - Query reserved regions
In SwiftUI, query reserved regions with the new reservedRegion method on a GeometryProxy from GeometryReader or the onGeometryChange modifier. In UIKit, use the reservedRegion method on UIView. Query a region's frame to incorporate it into your layout. The fold is backed by a division region, because it divides a larger area into smaller ones.
- 7:50 - Division and occlusion regions
Regions can be active or inactive; only active ones are returned by default, but the includeInactive query option surfaces the rest. The fold's division region is active only when the device is folded, and has zero width when flat — inactive regions still support high-level decisions, like preferring an even number of grid columns. Occlusion regions occlude rather than divide, and represent the FaceTime camera.
- 8:39 - System containers that adapt
Navigation containers like NavigationStack, NavigationSplitView, and TabView provide common navigation patterns, while content containers like List and ScrollView hold your content. Both adapt to the fold for free.
- 9:20 - Introducing arrangements
A layout container sits between navigation and content containers, arranging two views according to a set of rules called an arrangement. Using the Podcasts Now Playing and transcript views as an example, an arrangement is a function of inputs — size classes, the view's aspect ratio, and any active division regions — to outputs, like whether to show a view and what frame it gets. iOS 27.1 makes system-provided arrangements available in your app.
- 11:17 - Build with ArrangementView
An ArrangementView takes a primary and a secondary view — here a player view and an up-next view — and goes inside a NavigationStack. In UIKit, use UIArrangementViewController as the root view controller of your UINavigationController, configuring the primary and secondary view controllers.
- 12:00 - Configure the split arrangement
Set the preferred arrangement with the arrangementViewStyle modifier; the default split style divides its bounds between the primary and secondary views. It splits horizontally when the view is wider than it is tall and vertically when taller. Restrict this with the axes method, and note that when the arrangement can't split along its primary axis it shows only a single view. In UIKit, use the update arrangement method with UISplitArrangement.
- 13:21 - Use the overlay arrangement
Unlike split, the overlay arrangement prefers positioning content above or below, moving to side by side when the device folds. Query the overlayArrangementZIndex environment property to respond as the user folds and unfolds — useful for switching between collapsed and expanded versions of a view. In UIKit, use the state for view placement method on UIArrangementViewController and read the returned state's Z index.
- 14:39 - Choose between arrangements
Follow your app's existing patterns: HStack or VStack layouts translate to the split arrangement, ZStack layouts to overlay. Without an existing pattern, choose overlay when there's a clear foreground/background relationship — as in Accessibility Reader, where partially obscuring scrollable content is acceptable — and split when there's a main/detail relationship, as with the Podcasts transcript where neither view should be obscured.
- 16:09 - When not to use an arrangement
ArrangementViews don't provide navigation infrastructure, so avoid putting navigation containers like NavigationSplitView inside one. Because of how List and ScrollView behave, avoid putting an ArrangementView inside a scrollable container.
- 16:34 - Next steps
Audit your app's centered layouts and consider whether a two-column layout or a displacement pattern fits. Standard system containers and presentations give you a lot of behavior for free. For custom horizontal split or overlay layouts, consider ArrangementView, and adopt the ReservedRegions API for your highest-priority manually laid out controls.