Mobile Engineering

iPhone Duo SwiftUI/UIKit layout audit: 12 checks to survive outer, inner and half‑folded states

iPhone Duo breaks the old ‘phone-first’ contract: the same iPhone app can move between two displays and several poses, with bars that relocate and reserved regions you must avoid. This 12‑point audit turns Apple’s Duo guidance into a concrete checklist of what to delete, what to refactor, and what to test.

iPhone Duo breaks a decade of ‘phone-first’ assumptions: your UI can move between an outer and inner display, resize through multiple poses, and relocate system bars vertically while your code is still running. If your app branches on idiom/orientation or bakes in “status bar + notch + bottom tab bar” geometry, the Duo simulator in Xcode/iOS 27.1 will find it quickly. (apple.com)

What changed (and why your existing heuristics fail)

Apple’s Duo guidance is consistent across the HIG and the Tech Talks: treat layout as a continuum, avoid extreme pose-specific redesigns, and stop guessing device capabilities from idiom. The same interface may need to look reasonable on the outer display, expand to the inner display, and remain usable while partially open (Apple calls these configurations “poses”). (developer.apple.com)

Two practical consequences show up in real audits:

  • Your “phone” canvas can become iPad-like (regular/regular trait combinations can appear where your code previously only saw compact width), so orientation-gated layouts can do the wrong thing on a much larger surface.
  • The system’s bars are no longer where you expect. On Duo, navigation/toolbar/tab bar controls can coexist within a shared region, and Apple wants you to lean on system bar items and their compression/overflow rules rather than recreating bars yourself. (developer.apple.com)

This is why teams that were “responsive enough” for iPhone rotation still get bitten: the failure mode isn’t a single missed constraint; it’s a wrong mental model.

The 12-point audit (what to delete, what to refactor, what to test)

Treat this as a single pass through your UI layer. The order matters: delete brittle conditionals first, then adopt the containers that make Duo adaptation automatic, then add pose-specific refinements only where you can justify them.

1) Delete idiom-based layout forks

If you have any of the following driving layout decisions, assume it is wrong on Duo:

  • UIDevice.current.userInterfaceIdiom == .pad / .phone
  • SwiftUI horizontalSizeClass used as a proxy for “iPad mode”
  • “iPad layout” vs “iPhone layout” view hierarchies

Apple explicitly advises against assuming display size/capabilities from idiom, because Duo can blur those boundaries as it moves between displays/poses. (developer.apple.com)

Replacement:

  • Drive layout from available space and containers (NavigationSplitView / split patterns / arrangement containers), not device type.

2) Delete orientation-driven layout logic (especially ‘portrait == phone UI’)

Hard bans for Duo readiness:

  • UIDevice.orientationDidChangeNotification
  • UIDevice.current.orientation controlling view hierarchy
  • Assuming portrait implies compact width

Orientation can change without meaningfully describing the usable region on a foldable, and pose changes can be the bigger driver. If you need to react, react to size/geometry changes, not the accelerometer’s opinion.

Replacement:

  • SwiftUI: rely on adaptive containers and GeometryReader only when you need geometry.
  • UIKit: rely on trait/size transitions and constraints that recompute with size.

3) Stop caching screen sizes (and stop using UIScreen.main as layout input)

A common “works on every iPhone” pattern is:

  • Read screen bounds once at launch
  • Derive column counts / breakpoints
  • Never revisit

On Duo, the active display and usable region can change. Your layout must be able to recompute from the current container size.

Replacement:

  • Prefer view-local measurements (SwiftUI layout system, Auto Layout constraints) over global screen measurements.

4) Refactor: put your primary screens inside system containers

The quickest way to get Duo behaviour “for free” is to be inside Apple’s containers, because the platform can then move bars, manage insets, and adapt UI without you fighting it.

Audit your app’s top-level composition:

  • SwiftUI: NavigationStack, TabView, NavigationSplitView where appropriate.
  • UIKit: UINavigationController, UITabBarController, standard bar items.

Teams that replaced bars with custom chrome have more work, because custom toolbars aren’t automatically considered for vertical bar placement and compression behaviours. (developer.apple.com)

5) Delete custom navigation/toolbar/tab bars unless you have a hard requirement

This is the most painful one culturally, and the highest ROI technically.

If you built:

  • A bespoke top bar for brand reasons
  • A custom bottom bar to “avoid UIKit limitations”
  • Custom overflow menus

…you now own re-implementing all the Duo behaviours: vertical bars, compression, overflow, and the shared control region.

Apple’s Duo bar guidance pushes you towards standard items and the new compression controls rather than custom chrome. In SwiftUI, toolbarVerticalCompressionBehavior(_:) controls what compresses first when space is limited. (developer.apple.com)

When the answer is “do not do this”:

  • Do not ship a custom bar that assumes horizontal placement or fixed heights, then patch it with pose/orientation switches.

6) Make overflow a first-class state, not a bug

On Duo, overflow happens more often: narrow outer-display situations, keyboards, and bar co-location all raise the odds that your actions won’t fit.

Audit for:

  • Toolbars where every action is “always visible”
  • Text+icon buttons that duplicate meaning
  • Actions hidden behind bespoke “more” buttons

Replacement:

  • Prefer system overflow patterns (SwiftUI’s overflow/menu patterns; UIKit’s supported overflow APIs) rather than custom.
  • Decide explicitly whether you prefer toolbar items or tab bar items to compress first using the compression behaviour APIs. (developer.apple.com)

7) Adopt Duo-safe “reserved region” avoidance where you truly need exact geometry

Duo introduces the practical problem that “safe area” is no longer the whole story: there can be reserved regions you should not place content under (think fold/hinge-adjacent areas and other hardware-driven exclusions).

Apple’s Duo material points developers to use arrangement/region APIs for layout decisions instead of keying behaviour off sensors like hinge angle. (developer.apple.com)

Concrete audit steps:

  • SwiftUI: identify any screen that places tappable UI near edges/fold-adjacent areas; add instrumentation using GeometryProxy.reservedRegions(...) and update hit areas / padding accordingly. (apple-docs.everest.mt)
  • UIKit: similarly audit views doing manual layout and use the UIKit reserved-region counterparts (where available) instead of hard-coded insets. (apple-docs.everest.mt)

Trade-off:

  • Reserved region integration is extra code; don’t sprinkle it everywhere. Use it for interaction-critical chrome (camera controls, editors, media transport) where “nearly right” becomes “miss-tap”.

8) Refactor: replace “big layout swaps” with adaptive split/overlay patterns

The HIG explicitly advises avoiding extreme layout changes when folding/unfolding. (developer.apple.com)

This is where many apps currently do something like:

  • Compact: one-column list
  • Regular: entirely different screen with new navigation

On Duo, a better pattern is:

  • Keep the same information architecture
  • Use adaptive split/secondary panes when space allows

This reduces the cognitive discontinuity as the device changes pose, and usually reduces your own branching logic.

9) Ensure state restoration survives pose/display transitions

The “it feels finished vs fragile” line on Duo is often state continuity, not layout pixels.

Audit:

  • In-progress forms and editors: does focus/selection survive a size/scene change?
  • Navigation stacks: do you accidentally reset to root on a resize?
  • Media: does playback UI detach or reinitialise when geometry changes?

Rule of thumb:

  • If a pose change causes you to reconstruct view controllers/views from scratch, you will lose state unless you design for it.

10) Validate corner and shape handling on the inner display (stop hard-coding radii)

Duo pushes more UI into corners and along curved shapes. Apple has been nudging developers away from “fetch corner radius numbers” and towards concentricity-based APIs.

Audit:

  • Any custom rounded container that hard-codes radii
  • Any clipping masks that assume rectangular screens

Replacement:

  • SwiftUI: ConcentricRectangle and containerShape(_:) for concentric rounding. (developer.apple.com)
  • UIKit: UICornerConfiguration for mapping radii in a device-consistent way. (developer.apple.com)

11) If you support multi-window/secondary display experiences, respect the platform rules

Duo introduces new patterns around using both displays and multiple scenes, but Apple’s Tech Talk guidance includes constraints (for example, new windows can’t be created on the outer display; they’re reserved for the inner display). (developer.apple.com)

Audit:

  • Any “open in new window” feature you carried over from iPad
  • Any external display assumptions you’re reusing for Duo

Rule:

  • Keep your default app experience single-scene and adaptive first; treat multi-scene as an enhancement you gate behind real UX value.

12) Update your test matrix: test poses, not just devices and rotations

A Duo-ready QA pass is not “iPhone 16 portrait/landscape plus iPad”. It is a pose matrix.

Minimum regression set for each critical flow:

  • Outer display: portrait + landscape
  • Inner display: portrait + landscape
  • Partially open: the half-folded pose(s) you care about (especially for two-pane/overlay behaviours)
  • With keyboard visible (text entry)
  • With dynamic type bumped (at least one accessibility size)

Apple’s own messaging frames Duo as content that reacts as it folds and reorients, so you’re validating continuity as much as correctness. (apple.com)

What we typically remove first (to stop the bleeding)

If you want the “48-hour triage” list before you do a deeper redesign, it’s this:

  • Delete orientation notifications and orientation-gated view hierarchy swaps.
  • Remove screen-size caching.
  • Replace custom bars with system bars (or at least system items) so the platform can do vertical placement and overflow.
  • Move layout decisions into adaptive containers (split/stack) rather than if iPad / if landscape.

These changes are not glamorous, but they de-risk the rest of the Duo work because they reduce the number of bespoke layout rules you need to keep consistent across poses.

If your UI is built on system containers and standard bars, Duo mostly becomes “fix the few screens doing manual layout”, not “rewrite the app”. (github.com)

A note on Xcode/iOS 27.1 reality

Apple’s Tech Talks and developer materials are landing alongside early simulator support for iPhone Duo in Xcode 27.1, and teams are already discovering that some of the new layout symbols are tied to that toolchain. In practice, this can force a branch-and-test workflow even if your shipping App Store build stays on the current stable Xcode until Duo support is fully mainstream. (reddit.com)

The engineering decision for a 20–500 person company is less “can we support Duo?” and more “can we support Duo without forking UI code for the next two years?”. The audit above is designed to keep you on the adaptive path.

Where Codeversols fits (briefly, and honestly)

If you’re already deep in SwiftUI/UIKit and you just need a Duo readiness pass, the work is usually a focused audit plus targeted refactors on the handful of screens that still do manual layout or custom chrome. Codeversols teams typically approach this as: remove brittle branching, migrate to adaptive containers where it pays off, then add pose-specific refinements only where the UX genuinely benefits.

Close

iPhone Duo isn’t “another screen size”. It’s Apple making good on a long-running direction: stop coding to devices, start coding to adaptive containers, regions, and system behaviours. Run the 12 checks, delete the layout heuristics that served you on slab phones, and your app will not just survive Duo’s outer/inner/half-folded states — it will be simpler to maintain on every iPhone that comes after.

More From Our Blog

Android 16 (API 36) edge-to-edge is enforced: the window insets contract your UI must satisfy
Mobile Engineering • Oct 16, 2026

Android 16 (API 36) edge-to-edge is enforced: the window insets contract your UI must satisfy

Targeting Android 16 (API 36) removes the practical opt-out from enforced edge-to-edge. The only stable fix is to define a single owner for each inset (status bars, navigation bars, display cutout, IME) and test for double-application in CI.

Read more →
TestFlight ‘Waiting for Review’ for days? Ship anyway with a dual‑lane release pipeline (and what to automate in App Store Connect)
Mobile Engineering • Oct 15, 2026

TestFlight ‘Waiting for Review’ for days? Ship anyway with a dual‑lane release pipeline (and what to automate in App Store Connect)

When TestFlight Beta App Review and App Store Review queues stall, you don’t need to miss your launch date. This playbook describes a dual‑lane pipeline (internal TestFlight vs external TestFlight vs App Store), deterministic rollout rules, and the App Store Connect automation to keep shipping under review latency.

Read more →
Swift 6 strict concurrency default isolation footguns: how teams accidentally @MainActor their whole app (and a CI check to prove it)
iOS / Swift • Oct 14, 2026

Swift 6 strict concurrency default isolation footguns: how teams accidentally @MainActor their whole app (and a CI check to prove it)

Swift 6’s strict concurrency checks get teams over the line, but one build setting can quietly turn large parts of your app into MainActor-only code. Here’s how that happens, how it shows up as UI jank, and a simple CI audit that catches “main-actor creep” early.

Read more →