Apple has made iPhone apps meaningfully resizable in iPhone Mirroring and on iPad, and that breaks a lot of “it’s always 390pt wide” thinking. If you wait for QA to stumble on it, you’ll ship layouts that look fine on device and fall apart the moment the window becomes narrower, wider, or simply ‘not the size you coded for’. (developer.apple.com)
This article is a concrete 90‑minute audit we run on UIKit and mixed UIKit/SwiftUI apps to surface the eight most common assumptions that explode under resizing, with fixes that don’t require a full redesign.
What changed (and why this is suddenly urgent)
WWDC26 explicitly called out support to resize iOS apps in iPhone Mirroring and on iPad, and positioned resizable Simulator/Previews plus iPhone Mirroring as the new normal testing loop. (developer.apple.com)
Xcode 27’s Device Hub workflow also nudges you into this: Apple’s own materials explicitly mention resizing the iPhone Mirroring window on macOS 27 and using that mode to check your app. (developer.apple.com)
Two practical implications that catch teams out:
- Your app can be fully resizable but still be running under the phone idiom. If your branching logic is “if phone do X else do Y”, it may do X in a non-phone-sized window. (developer.apple.com)
- You can no longer treat resizability as “iPad multitasking only”. iPhone Mirroring windows can be resized, and Apple Support documentation explicitly describes resizing the mirroring window. (support.apple.com)
The 90‑minute audit: setup and a strict pass/fail definition
You’re trying to find “assumptions”, not polish. The rule for the audit is simple:
- Pass: the UI remains usable (no clipped primary actions, no overlapped text, no unreachable content) across a reasonable range of widths.
- Fail: any core screen produces clipped navigation/actions, overlapping content, or a layout that can’t be scrolled to reach controls.
A practical workflow that matches Apple’s direction:
- Pick 6–10 “money screens”: onboarding/login, your core list/grid, detail view, composer/editor, checkout/paywall, settings, and any screen with a custom header.
- Run the app.
- Enter a resize mode (Device Hub / resizable simulator workflow) and drag through a width sweep.
- For each failure, identify which of the eight assumptions you hit, then apply the minimal fix.
Apple explicitly points to testing in Device Hub and iPhone Mirroring as part of the “build with iOS 27 SDK, identify flexibility gaps” loop. (developer.apple.com)
Assumption 1: “UIScreen.main.bounds is my layout contract”
Failure mode: views sized from UIScreen.main.bounds (or cached screen widths) don’t track the actual window geometry. In a resizable context, you end up with:
- content that stays “iPhone-wide” inside a wider window (ugly but survivable), or
- content that overflows/clips inside a narrower window (unusable).
Do not do this: compute widths once at launch and store them globally.
Fix (UIKit): treat the view controller’s view as the source of truth.
- Prefer
view.bounds,view.safeAreaLayoutGuide, and constraints. - React in
viewWillLayoutSubviews/viewDidLayoutSubviewsif you must adjust constants. - For geometry-driven changes, use
viewWillTransition(to:with:)or observetraitCollectionDidChangeplus layout passes — but base decisions on size, not idiom.
Fix (SwiftUI): avoid reading screen size from UIKit.
- Use
GeometryReadersparingly (local, not global) and design layouts that flow. - Prefer adaptive containers (
Grid,LazyVGrid,NavigationStack+ toolbars) over manual frame math.
Assumption 2: “Size class or phone idiom tells me how much space I have”
Failure mode: you gate UI structure on horizontalSizeClass or userInterfaceIdiom == .phone. In a resizable iPhone app window, you can have a “phone idiom” with non-phone widths, leading to:
- a cramped “phone layout” wasting space when wide
- a “tablet layout” forced into a narrow window when you flip a size-class threshold at the wrong time
WWDC26 explicitly warns that when your iPhone app runs on iPad or iPhone Mirroring, it can be fully resizable while still under the phone idiom. (developer.apple.com)
Fix: branch on available size, not device category.
- Use breakpoints on
view.bounds.width(UIKit) /containerRelativeFrameorViewThatFitspatterns (SwiftUI), and treat them like responsive web breakpoints. - Keep breakpoints small in number. Two or three per screen is usually enough.
Assumption 3: “My navigation bar / toolbar will always fit”
Failure mode: custom title views, stacks of bar button items, or “everything as a trailing item” toolbars collide under narrow widths.
This is one reason Apple keeps emphasising that system toolbars can reorganise items as the window resizes (and that SwiftUI apps get a lot of the behaviour automatically). (developer.apple.com)
Fix (UIKit):
- Prefer
UINavigationItem’s standard patterns (title,prompt,leftBarButtonItems,rightBarButtonItems) over fully custom container views. - Collapse low-priority actions into menus.
- Avoid hard-coded custom title widths.
Fix (SwiftUI):
- Prefer
ToolbarItem(placement:)and let the system prioritise. - Push secondary actions into
Menuand make sure primary actions survive at minimum width.
Quick check
- Resize to “uncomfortably narrow” and confirm you can still navigate back, search, and perform the primary action.
Assumption 4: “Safe area is stable; I can pin everything to the bottom”
Failure mode: bottom-anchored controls (especially custom tab bars or purchase CTAs) either:
- overlap scrollable content because the insets changed and you didn’t update content insets, or
- float awkwardly because you added inset twice
Fix (UIKit):
- For scroll views, set
contentInsetAdjustmentBehaviorintentionally (don’t accept defaults blindly). - Use
additionalSafeAreaInsetsonly with a clear reason, and verify you aren’t doubling insets with your own padding.
Fix (SwiftUI):
- Prefer system-safe constructs:
safeAreaInset(edge:)for persistent controls; avoid ad-hocpadding(.bottom, ...)with magic numbers.
Assumption 5: “Hard-coded widths are fine for ‘small’ components”
Failure mode: “small” fixed frames accumulate into a broken layout.
Common offenders:
- fixed-width buttons (“Continue”, “Subscribe”, localisation then breaks)
- fixed-width text fields inside horizontal stacks
- chips/tags with fixed spacing that can’t wrap
Fix:
- Make labels and buttons content-driven. Let them grow.
- Use compression resistance/hugging priorities (UIKit) or
layoutPriority(SwiftUI) to protect what matters. - Allow wrapping where wrapping is acceptable; otherwise switch to a vertical layout at a breakpoint.
Assumption 6: “This screen can’t scroll”
Failure mode: screens designed to fit a known height/width become non-functional when height shrinks or when toolbars consume more vertical space.
Fix:
- If it’s a form, make it scrollable. Even if “it always fit on iPhone before”.
- If it’s a two-column detail, allow it to become one column under a width threshold.
- Treat scrolling as a functional safety net, not a design failure.
Assumption 7: “Presentations are always full-screen”
Failure mode: custom presentation controllers, sheet detents, or modals that assumed full-screen start to look wrong when the window isn’t full-screen.
Apple’s WWDC26 UIKit modernisation guidance calls out that UIRequiresFullscreen is honoured on iPhone in resizable environments starting in iOS 27 — which is effectively Apple telling you “stop relying on fullscreen as a given”. (developer.apple.com)
Do not do this: set UIRequiresFullscreen to paper over layout problems. That opts you out of the direction the platform is going.
Fix:
- Ensure your sheet content has intrinsic sizing and scrolls.
- Verify popovers/menus anchor correctly in a resized window.
Assumption 8: “UIKit + SwiftUI hosting behaves like it did before”
Failure mode: mixed stacks often hide layout constraints in the seam:
UIHostingControllersized with an explicit frame that never updates- SwiftUI view using fixed frames because “UIKit will size it anyway”
- UIKit container not invalidating intrinsic content size when the SwiftUI content changes under width pressure
WWDC26’s SwiftUI updates explicitly mention that SwiftUI apps get a lot of resizability automatically, but mixed UIKit/SwiftUI apps may need additional consideration, and Apple points people to UIKit modernisation guidance for that reason. (developer.apple.com)
Fix:
- In UIKit, constrain the hosting controller’s view to the container edges; don’t drive it by frame.
- In SwiftUI, avoid fixed-size assumptions when embedded (test inside narrow containers).
- Add snapshot tests (or at least automated UI runs) that exercise multiple widths.
What to ship after the audit (and what not to)
After 90 minutes you should have a list of failures. Triage them by user impact.
- Fix immediately: anything that blocks navigation, primary actions, text entry, or reading key content.
- Fix next: visual polish issues that look “off” but remain usable.
- Defer: rare screens and internal tools, but only if they don’t break core flows.
What not to ship as a “fix”:
- A global
UIRequiresFullscreenflag. - Hard minimum window sizes enforced in code.
- Dozens of special cases keyed off specific device models.
The goal is one app that adapts to whatever canvas it’s given — exactly the framing Apple used when introducing iOS app resizability in mirroring and on iPad. (developer.apple.com)
A small, honest note on getting help
If you have a mature app with years of UIKit, a mixed UIKit/SwiftUI stack, and custom navigation/presentation, it’s common for this audit to find issues that cross-cut multiple screens (shared components, design system primitives, analytics wrappers, custom containers). That’s the kind of work we do at codeversols: short, surgical modernisation passes that leave you with fewer layout branches, better test coverage, and a UI that behaves under resizable iOS without a redesign.
Close
Resizable iOS isn’t a future edge case; Apple has made it a first-class behaviour in iPhone Mirroring and on iPad, and Xcode’s tooling is steering teams to test it early. (developer.apple.com)
Run the audit, categorise each failure into one of the eight assumptions above, and apply the smallest fix that makes the screen usable across widths. If you do that now, you’ll avoid the most expensive kind of UI work: emergency reactive layout rewrites triggered by a form factor you didn’t think you had to support.



