Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

iPad/iPhone - Display best practices….

So…I am hitting a wall here and could use some guidance towards best practice.

I’ve developed an app in Xcode/SwiftUI that renders just fine on the iPhone - text, images, buttons, frames…everything is nicely centered on the screen or scrolls where and when I want.

The iPad though…not so much. I’m having issues with tops and bottoms being cut off in scrollviews. These are just straight up text screens too - the ones with other elements/controls…they’re rendering fine.

I’ve tried a mix of geometry, vstack, scrollview, padding, spacers…the lot of it. Nothing I seem to do works - the views do not want to fill and fit properly.

And, of course, the issue becomes worse the moment you flip the iPad into landscape view. Or use the 13” models.

I’d imagine others are battling these issues as well and found solutions, so I decided to hit up the brain trust.

Answered by darkpaw in 837057022

All my apps work on both the iPhone and iPad, but due to the amount of changes - some structural - that are required to get an iPhone version to look and work properly on the iPad, I use two different views:

@main
struct MainApp: App {
    // ...
    var body: some Scene {
        WindowGroup {
            if(UIDevice.current.userInterfaceIdiom == .pad) {
                TabletView()
            } else {
                PhoneView()
            }
        }
    }
}

So, if the user is using an iPhone, the PhoneView() is the main entry point. For iPads, it's TabletView().

The reason I did this is because the iPad has much more space and allows me to do more things, so the TabletView has more things in it.

Also, I'd rather not have one big, unmanageable View full of if ... else statements and ternary operators.

It also means your spacers and padding values apply only to that device type.

Where the two views have similar UI, those bits are extracted into their own little View structs and called within those two main entry points.

When you separate out the two views you may find you're duplicating some work, but you'll also be working on a view that only applies to an iPad or an iPhone and not both. You can make a change in the TabletView and be assured it hasn't affected the PhoneView, so you haven't got to retest that change on the iPhone.

You can also then expand this to include Vision Pro, Apple TV, and any other device idioms Apple has or releases in future, and you won't need to add more and more if ... else and ternary operators in that one massive file.

If you're having issues with specific models of an iPad or iPhone I'd say you're maybe using too many magic numbers in your code? You've probably found that the padding on an iPhone 13 mini for some label is 5, while on an iPhone 14 Plus it's 12 so you've written that in. You should rework this to align things naturally using SwiftUI's HStacks, YStacks etc.

Or, have a consistent padding for your UI so that it looks the same on every device. Let's say you can fit 8 text fields vertically in a form on an iPhone 12 mini, and 10 on an iPhone 15 Pro, that's fine. You don't need to space everything out to always fit 8 fields on the screen, so the padding between the fields can be the same on every device.

If you want to show us an example of what's causing you issues, drop some code here (properly-formatted using the code formatting toolbar) and screenshots showing us the issue in the UI so we can visualise it.

Accepted Answer

All my apps work on both the iPhone and iPad, but due to the amount of changes - some structural - that are required to get an iPhone version to look and work properly on the iPad, I use two different views:

@main
struct MainApp: App {
    // ...
    var body: some Scene {
        WindowGroup {
            if(UIDevice.current.userInterfaceIdiom == .pad) {
                TabletView()
            } else {
                PhoneView()
            }
        }
    }
}

So, if the user is using an iPhone, the PhoneView() is the main entry point. For iPads, it's TabletView().

The reason I did this is because the iPad has much more space and allows me to do more things, so the TabletView has more things in it.

Also, I'd rather not have one big, unmanageable View full of if ... else statements and ternary operators.

It also means your spacers and padding values apply only to that device type.

Where the two views have similar UI, those bits are extracted into their own little View structs and called within those two main entry points.

When you separate out the two views you may find you're duplicating some work, but you'll also be working on a view that only applies to an iPad or an iPhone and not both. You can make a change in the TabletView and be assured it hasn't affected the PhoneView, so you haven't got to retest that change on the iPhone.

You can also then expand this to include Vision Pro, Apple TV, and any other device idioms Apple has or releases in future, and you won't need to add more and more if ... else and ternary operators in that one massive file.

If you're having issues with specific models of an iPad or iPhone I'd say you're maybe using too many magic numbers in your code? You've probably found that the padding on an iPhone 13 mini for some label is 5, while on an iPhone 14 Plus it's 12 so you've written that in. You should rework this to align things naturally using SwiftUI's HStacks, YStacks etc.

Or, have a consistent padding for your UI so that it looks the same on every device. Let's say you can fit 8 text fields vertically in a form on an iPhone 12 mini, and 10 on an iPhone 15 Pro, that's fine. You don't need to space everything out to always fit 8 fields on the screen, so the padding between the fields can be the same on every device.

If you want to show us an example of what's causing you issues, drop some code here (properly-formatted using the code formatting toolbar) and screenshots showing us the issue in the UI so we can visualise it.

No…you’re right; I‘m trying to fill two different sized holes with the same peg.

I was originally trying to do it all in a single file with a bit of formatting magic, but that just was not working. Much easier to just separate the two.

I made the main a file a stump to call two separate views - one for tablets, the other for phones - so it’s a reasonably non-intrusive change to the overall app structure. That will allow for some tablet-only features as well.

Sometimes ya just get locked in a loop…. Thanks for the breakout….

OK - I spoke too soon. I am STILL having issues the moment I flip into landscape mode on the iPad.

This version of the code works perfectly for a portrait view. Everything lines up nicely. Flip the iPad...it's as though it thinks it is still in portrait mode. Sure, you can scroll, but you can't even get to the top/bottom maybe fifth or so of the content.

What am I missing? It's something simple, I know - I've been beating my head on the wall with this for days and I don't think I can see the forest for the trees anymore.

EDIT: I take it all back - it's the background. The moment I give the background ".scaledToFill()" everything goes haywire in landscape mode.

iPad/iPhone - Display best practices….
 
 
Q