Your iPhone App Can Be Resized Now. Is It Ready?
Do you remember when rotating the phone felt like the hardest layout problem we would ever face? đ With iOS 27, someone can drag your iPhone app to pretty much any size they want, on their Mac or on their iPad.
So let me ask you something, and be honest. How many userInterfaceIdiom == .phone checks are sitting in your codebase right now?
Yeah. Me too. Letâs fix that together.
What actually changed in iOS 27
At WWDC26, Apple quietly dropped a big one. When your iPhone app runs in iPhone Mirroring on the Mac, or as an iPhone app on iPad, it is now fully resizable.
Here is the part that bites: it still runs under the phone user interface idiom.
Stop here for a minute.. Read that again. Your app says âIâm a phoneâ, and it can still be as wide as a Mac window.
In the Whatâs new in SwiftUI session, Apple also says that apps built with SwiftUI get a lot of this for free. Apps that mix UIKit and SwiftUI (which is most of our real-world apps, right?) have some extra homework. So letâs go through it one by one.
Why idiom checks are now lying to you
For years we have all written code like this:
if UIDevice.current.userInterfaceIdiom == .pad {
showSidebarLayout()
} else {
showCompactLayout()
}It worked because âphoneâ quietly meant âsmall screenâ. Not anymore.
Appleâs Modernize your UIKit app session says it very directly: the idiom trait is no longer meaningful for any kind of layout decision. Your app is expected to use the extra space well, whether it runs in the phone idiom or the pad idiom.
So the rules are now:
- Donât choose a layout by idiom.
- Donât treat âregular widthâ as âiPadâ.
- Donât compare bounds against known device sizes like
bounds.height == 844.
Size classes are the real answer
Ohhh wait!! This isnât new at all. Size classes have been here since iOS 8. Apple even quoted Bruce Nilo from WWDC 2014: âA device rotation is only an animated bounds change.â We just never had to take it seriously on iPhone.
In UIKit, read the size class from the trait collection:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if traitCollection.horizontalSizeClass == .regular {
showSidebarLayout()
} else {
showCompactLayout()
}
}In SwiftUI, read it from the environment:
struct LibraryView: View {
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
var body: some View {
if horizontalSizeClass == .regular {
HStack {
SidebarView()
ContentView()
}
} else {
NavigationStack {
ContentView()
}
}
}
}Use the size class to say what kind of experience you want (compact or roomy). When you need finer control, look at the actual space your view has. That brings us to the next point.
Orientation and UIScreen.main are next on the hit list
There are two more habits we need to drop.
1. Interface orientation
In iOS 27, the interface orientations your app supports are only a preference, and the system ignores them in resizable environments. In iPhone Mirroring on the Mac, your app always runs in portrait orientation, whatever the windowâs shape is.
So if isLandscape { ⌠} for layout? Gone. Use size classes instead.
2. Screen bounds
In a resizable world, your scene rarely gets the full screen. So any UIScreen.main.bounds in your layout code is a bug waiting to happen.
// Before
let width = UIScreen.main.bounds.width
// After
let width = view.bounds.widthReading the size once at launch isnât enough, because the size can change in the middle of a session. Do size-dependent layout in viewDidLayoutSubviews (or layoutSubviews). For work that should run when the size changes, use viewWillTransition(to:with:).
Get Boudhayan Biswasâs stories in your inbox
Join Medium for free to get updates from this writer.
If you need the scene-level picture, Apple points to the window sceneâs effective geometry. You can observe it in your scene delegate:
func windowScene(_ windowScene: UIWindowScene,
didUpdateEffectiveGeometry previousEffectiveGeometry: UIWindowScene.Geometry) {
let newSize = windowScene.effectiveGeometry.coordinateSpace.bounds.size
// React to the new available space
}Mixed UIKit + SwiftUI apps hurt the most
Pure SwiftUI layouts mostly adapt by themselves. Hybrid apps are where things go wrong. Think of a UIKit container that measures the screen once, hosting a SwiftUI view that expects to adapt, or a SwiftUI screen embedding a UIKit view that checks idiom.
In SwiftUI, if you need the actual size, use onGeometryChange:
struct HeroPlayerView: View {
@State private var isWide = false
var body: some View {
PlayerSurface()
.aspectRatio(16 / 9, contentMode: isWide ? .fit : .fill)
.onGeometryChange(for: Bool.self) { proxy in
proxy.size.width > proxy.size.height
} action: { newValue in
isWide = newValue
}
}
}A small note from the video side
I have spent a good chunk of my career on video playback, so this one is close to my heart. đŹ
Hero images and video set to .scaleAspectFill (or .aspectRatio(contentMode: .fill)) look great on a phone in portrait. Now stretch that window wide on a Mac and suddenly the top and bottom of your content are gone. Subtitles get clipped, faces get cropped, and the important part of the frame isn't visible.
Video is one of the first places where a âphone-shapedâ assumption shows up. Pick fill or fit based on the current size class or aspect ratio, not on the device. Then test it at sizes your design team never drew.
Opting out isnât really opting out anymore
âCan I just set UIRequiresFullScreen and go home?" đ
Not really. Starting in iOS 27, UIRequiresFullScreen is honoured on iPhone in resizable environments, but it no longer opts your app out of resizing. Instead, you get discrete resizing. While someone drags the window, the scene doesn't resize live. When they let go, the system moves the scene to a new screen configuration that matches that size.
This exists mostly for games, which need to render at full quality. For a regular app, it only delays the work. Appleâs technote TN3192 also notes that UIRequiresFullScreen has been deprecated since iPadOS 26.
Test it before your users do
Now the fun part. In Xcode 27, iOS previews have a new Resizable Canvas mode.
- Click the Resizable button in the lower-left corner of the canvas.
- Drag a handle on the top, bottom, or sides of the preview to resize it.
- Or type exact dimensions at the bottom of the canvas.
This lets you see how your app behaves in iPhone Mirroring or on iPad without leaving your editor. Drag it wide, drag it narrow, drag it into a weird square. Then watch what breaks.
Recap
Hereâs your checklist:
- Search for
userInterfaceIdiomand replace layout decisions with size classes. - Search for
UIScreen.mainand replace it withview.bounds,window.bounds, or the scene's effective geometry. - Remove orientation checks from your layout code.
- Remove hard-coded device sizes.
- Choose fill or fit for media based on the space available.
- Donât rely on
UIRequiresFullScreenas an escape hatch. - Test with Resizable Canvas in Xcode 27.
Why wait? Go and grep your codebase now! And tell me in the comments what the weirdest idiom hack you found was. Iâm sure we all have one.
Rotation was always just a bounds change. Now itâs every change.
Cheers!!! Thank you for reading!!








