iOS 6 apps - how to deal with iPhone 5 screen size? [duplicate]
Asked Answered
P

8

265

Possible Duplicate:
How to develop or migrate apps for iPhone 5 screen resolution?

I was just wondering with how should we deal with the iPhone 5 bigger screen size.

As it has more pixels in height, things like GCRectMake that use coordinates (and just doubled the pixels with the retina/non retina problem) won't work seamlessly between versions, as it happened when we got the Retina.

And will we have to design two storyboards, just like for the iPad?

I personally don't think Apple will require you to check the screen size every time you have to draw something, like many answers say. Does that happen with the iPad?

Psephology answered 12/9, 2012 at 21:40 Comment(2)
You just add the 4-inch Default.png and your app forthwith takes up the full 4-inch screen size.Osmen
Counterintuitive though it may be, simply adding a retina (4-inch) launch image, as per Pascal's suggestion, removes the black area flanking the app view, giving full-screen on both retina-4 and previous devices.Caliche
L
209

All apps will continue to work in the vertically stretched screen from what I could tell in today's presentation. They will be letterboxed or basically the extra 88 points in height would simply be black.

If you only plan to support iOS 6+, then definitely consider using Auto Layout. It removes all fixed layout handling and instead uses constraints to lay things out. Nothing will be hard-coded, and your life will become a lot simpler.

However, if you have to support older iOS's, then it really depends on your application. A majority of applications that use a standard navigation bar, and/or tab bar, could simply expand the content in the middle to use up that extra points. Set the autoresizing mask of the center content to expand in both directions.

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

It works great out of the box for table views, however, if your app used pixel-perfect layout for displaying content, then your best bet would be to re-imagine the content so that it can accommodate varying heights.

If that's not a possibility, then the only remaining option is to have two UIs (pre iPhone 5, and iPhone 5).

If that sounds ugly, then you could go with the default letterboxed model where the extra points/pixels just show up black.

Edit

To enable your apps to work with iPhone 5, you need to add a retina version of the launcher image. It should be named [email protected]. And it has to be retina quality - there's no backward compatibility here :)

You could also select this image from within Xcode. Go to the target, and under the Summary section, look for Launch Images. The image has to be 640x1136 pixels in size. Here's a screenshot of where to find it, if that helps.

Xcode screenshot

Laudatory answered 12/9, 2012 at 22:2 Comment(4)
I think UIActionSheet is broken in iOS6 on non-tall iPhones, if you use this method, and don't do anything special to fix the action sheets. If I set my main nibs to be tall, that is the only thing that is broken.Bullheaded
xcode automatically renames your image to [email protected] so you dont have to name it yourself like that. just make an image on photoshop 640x1136 and drag and drop it into the designated area in your project.Mannish
@DaGaMs Alternatively you can add self.window.frame = [UIScreen mainScreen].bounds; to the top of your -application:didFinishLaunchingWithOptions:.Thruway
Besides if view contains subviews then view's autoresizesSubviews need to set to YES as well.Sanderling
G
84

You need to add a 640x1136 pixels PNG image ([email protected]) as a 4 inch default splash image of your project, and it will use extra spaces (without efforts on simple table based applications, games will require more efforts).

I've created a small UIDevice category in order to deal with all screen resolutions. You can get it here, but the code is as follows:

File UIDevice+Resolutions.h:

enum {
    UIDeviceResolution_Unknown           = 0,
    UIDeviceResolution_iPhoneStandard    = 1,    // iPhone 1,3,3GS Standard Display  (320x480px)
    UIDeviceResolution_iPhoneRetina4    = 2,    // iPhone 4,4S Retina Display 3.5"  (640x960px)
    UIDeviceResolution_iPhoneRetina5     = 3,    // iPhone 5 Retina Display 4"       (640x1136px)
    UIDeviceResolution_iPadStandard      = 4,    // iPad 1,2,mini Standard Display   (1024x768px)
    UIDeviceResolution_iPadRetina        = 5     // iPad 3 Retina Display            (2048x1536px)
}; typedef NSUInteger UIDeviceResolution;

@interface UIDevice (Resolutions)

- (UIDeviceResolution)resolution;

NSString *NSStringFromResolution(UIDeviceResolution resolution);

@end

File UIDevice+Resolutions.m:

#import "UIDevice+Resolutions.h"

@implementation UIDevice (Resolutions)

- (UIDeviceResolution)resolution
{
    UIDeviceResolution resolution = UIDeviceResolution_Unknown;
    UIScreen *mainScreen = [UIScreen mainScreen];
    CGFloat scale = ([mainScreen respondsToSelector:@selector(scale)] ? mainScreen.scale : 1.0f);
    CGFloat pixelHeight = (CGRectGetHeight(mainScreen.bounds) * scale);

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
        if (scale == 2.0f) {
            if (pixelHeight == 960.0f)
                resolution = UIDeviceResolution_iPhoneRetina4;
            else if (pixelHeight == 1136.0f)
                resolution = UIDeviceResolution_iPhoneRetina5;

        } else if (scale == 1.0f && pixelHeight == 480.0f)
            resolution = UIDeviceResolution_iPhoneStandard;

    } else {
        if (scale == 2.0f && pixelHeight == 2048.0f) {
            resolution = UIDeviceResolution_iPadRetina;

        } else if (scale == 1.0f && pixelHeight == 1024.0f) {
            resolution = UIDeviceResolution_iPadStandard;
        }
    }

    return resolution;
 }

 @end

This is how you need to use this code.

1) Add the above UIDevice+Resolutions.h & UIDevice+Resolutions.m files to your project

2) Add the line #import "UIDevice+Resolutions.h" to your ViewController.m

3) Add this code to check what versions of device you are dealing with

int valueDevice = [[UIDevice currentDevice] resolution];

    NSLog(@"valueDevice: %d ...", valueDevice);

    if (valueDevice == 0)
    {
        //unknow device - you got me!
    }
    else if (valueDevice == 1)
    {
        //standard iphone 3GS and lower
    }
    else if (valueDevice == 2)
    {
        //iphone 4 & 4S
    }
    else if (valueDevice == 3)
    {
        //iphone 5
    }
    else if (valueDevice == 4)
    {
        //ipad 2
    }
    else if (valueDevice == 5)
    {
        //ipad 3 - retina display
    }
Grind answered 12/9, 2012 at 21:40 Comment(6)
Just a few suggestions: 1) you may want to actually test for height==568*2 before reporting iPhoneTallerHiRes and 2) you may want to also test the width. Then for everything not explicitly recognized return UIDevice_notRecognizedRes. Should be easier to adapt in case the future iPhone >5 or a new "the new iPad" has yet another screen size.Rhododendron
ps. Taking this kind of logic further, you may also want to explicitly check for UIUserInterfaceIdiomPad instead of assuming that !phone == pad.Rhododendron
Approved Evan Schoenberg's edit request to fix behavior on standard resolution iPhones on iOS 4 and later. Edited code is in a fork of malcommac's git repository: github.com/evands/iOSUtilities/tree/main/UIDevice+Resolutions (Moving the context into the comments instead of the question body itself)Minter
Careful using Apple's known class prefixes.Hootman
@FatihArslan - that is not how you use this function. This is incorrect "[UIDevice currentResolution] == UIDevice_iPhoneTallerHiRes" Can anyone tell me how to use this function correctly????Chaves
since you already defined en enum, why not use a nice switch case with the enum instead of this magic numbered if?Sarto
B
56

I have just finished updating and sending an iOS 6.0 version of one of my Apps to the store. This version is backwards compatible with iOS 5.0, thus I kept the shouldAutorotateToInterfaceOrientation: method and added the new ones as listed below.

I had to do the following:

Autorotation is changing in iOS 6. In iOS 6, the shouldAutorotateToInterfaceOrientation: method of UIViewController is deprecated. In its place, you should use the supportedInterfaceOrientationsForWindow: and shouldAutorotate methods. Thus, I added these new methods (and kept the old for iOS 5 compatibility):

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAllButUpsideDown;    
}
  • Used the view controller’s viewWillLayoutSubviews method and adjust the layout using the view’s bounds rectangle.
  • Modal view controllers: The willRotateToInterfaceOrientation:duration:,
    willAnimateRotationToInterfaceOrientation:duration:, and
    didRotateFromInterfaceOrientation: methods are no longer called on any view controller that makes a full-screen presentation over
    itself
    —for example, presentViewController:animated:completion:.
  • Then I fixed the autolayout for views that needed it.
  • Copied images from the simulator for startup view and views for the iTunes store into PhotoShop and exported them as png files.
  • The name of the default image is: [email protected] and the size is 640×1136. It´s also allowed to supply 640×1096 for the same portrait mode (Statusbar removed). Similar sizes may also be supplied in landscape mode if your app only allows landscape orientation on the iPhone.
  • I have dropped backward compatibility for iOS 4. The main reason for that is because support for armv6 code has been dropped. Thus, all devices that I am able to support now (running armv7) can be upgraded to iOS 5.
  • I am also generation armv7s code to support the iPhone 5 and thus can not use any third party frameworks (as Admob etc.) until they are updated.

That was all but just remember to test the autorotation in iOS 5 and iOS 6 because of the changes in rotation.

Bawdy answered 13/9, 2012 at 0:13 Comment(8)
My app already had a resizable view but still launched in letterbox. Even if I changed the width of my view to 568, it still launched letterboxed (and squished, to boot)! As soon as I added a [email protected], it launched at the proper aspect ratio.Batchelor
If you want to support both iOS 5 autorotation and ios 6 autorotation, do you include the new methods in addition to the old autorotation methods in the same file?Medicable
andrewx, Yes. You support both the old (leave in your previous methods) and add the new ones above. Then, when running iOS 5 it will call the old ones and iOS 6 calls the new ones.Bawdy
Hey guys! I've added the two methods for autorotation but no autorotation happen. The screen remains in portrait when I tilt the device... what's the problem here?Hobbs
Did you select rotations on the Target -> Summary page?Bawdy
@HannesSverrisson Yes sorry, you are correct. Long nights + stress = not reading things properly. :-)Carcinoma
Thanks! Working to apply this to a UITabBarController situation (each tab leading to a UINavigationController).Wow
although i am using both methods for changing orientations on both ios6 and ios5, my app is autorotating on ios6. On ios5 i am stack with portrait and i can not figure out why. Please se my question #12755422Doyle
A
26

No.

if ([[UIScreen mainScreen] bounds].size.height > 960)

on iPhone 5 is wrong

if ([[UIScreen mainScreen] bounds].size.height == 568)
Aldenalder answered 14/9, 2012 at 13:30 Comment(3)
why 568?? Please explain me this. ThanksMireielle
The iPhone 5 screen resolution is 1136x640; however all dimensions are in 2-pixel units to be consistent with the original iPhone screen - Apple doubled the number of pixels in each direction in the iPhone 4, but wanted all software to run unaltered. So 568 is the height of the new screen (= 1136/2).Osmosis
I like this approach because it's a one liner and the "hard coded" 568 matches Apple's naming conventions for device specific launch images. For example [email protected]. Apple Docs: App Launch (Default) Images.Malignant
M
17
@interface UIDevice (Screen)
typedef enum
{
    iPhone          = 1 << 1,
    iPhoneRetina    = 1 << 2,
    iPhone5         = 1 << 3,
    iPad            = 1 << 4,
    iPadRetina      = 1 << 5

} DeviceType;

+ (DeviceType)deviceType;
@end

.m

#import "UIDevice+Screen.h"
@implementation UIDevice (Screen)

+ (DeviceType)deviceType
{
    DeviceType thisDevice = 0;
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
    {
        thisDevice |= iPhone;
        if ([[UIScreen mainScreen] respondsToSelector: @selector(scale)])
        {
            thisDevice |= iPhoneRetina;
            if ([[UIScreen mainScreen] bounds].size.height == 568)
                thisDevice |= iPhone5;
        }
    }
    else
    {
        thisDevice |= iPad;
        if ([[UIScreen mainScreen] respondsToSelector: @selector(scale)])
            thisDevice |= iPadRetina;
    }
    return thisDevice;
}

@end

This way, if you want to detect whether it is just an iPhone or iPad (regardless of screen-size), you just use:

if ([UIDevice deviceType] & iPhone) 

or

if ([UIDevice deviceType] & iPad)

If you want to detect just the iPhone 5, you can use

if ([UIDevice deviceType] & iPhone5)

As opposed to Malcoms answer where you would need to check just to figure out if it's an iPhone,

if ([UIDevice currentResolution] == UIDevice_iPhoneHiRes || 
    [UIDevice currentResolution] == UIDevice_iPhoneStandardRes || 
    [UIDevice currentResolution] == UIDevice_iPhoneTallerHiRes)`

Neither way has a major advantage over one another, it is just a personal preference.

Misdemean answered 13/9, 2012 at 17:6 Comment(3)
This didn't work for me at all, maybe I'm missing something but if ([UIDevice deviceType] & iPhone5) returned true for me on any device, no matter the screen size?Generatrix
Sorry about that. I've made changes.Misdemean
If its a retinia ipod it will return iPhoneRetina. If it's a tall ipod it will return iPhone5. If it's a low res iphone it will return iPhone.Misdemean
O
5

@Pascal's comment on the OP's question is right. By simply adding the image, it removes the black borders and the app will use the full height.

You will need to make adjustments to any CGRects by determining that the device is using the bigger display. I.e. If you need something aligned to the bottom of the screen.

I am sure there is a built in method, but I haven't seen anything and a lot is still under NDA so the method we use in our apps is quite simply a global function. Add the following to your .pch file and then its a simple if( is4InchRetina() ) { ... } call to make adjustments to your CGRects etc.

static BOOL is4InchRetina()
{
    if (![UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 548 || [UIApplication sharedApplication].statusBarHidden && (int)[[UIScreen mainScreen] applicationFrame].size.height == 568)
        return YES;

    return NO;
}
Octofoil answered 14/9, 2012 at 14:27 Comment(1)
Untested, but there might be a bug in this for when the iPhone has a double size statusbar. EG, when in a phonecall.Misdemean
E
3

I think you can use [UIScreen mainScreen].bounds.size.height and calculate step for your objects. when you calculate step you can set coordinates for two resolutions.

Or you can get height like above and if(iphone5) then... else if(iphone4) then... else if(ipad). Something like this.

If you use storyboards then you have to create new for new iPhone i think.

Eleonoreeleoptene answered 12/9, 2012 at 21:44 Comment(4)
This makes sense, but as I said above, don't you think apple will create something easier?Psephology
Hmmm i don't know. It's not the same like with iPhone and iPhone Retina. This screen has more pixels in height so proportions aren't the same. On keynote was showed (if i remember) that old applications are centered and has black straps above and below.Eleonoreeleoptene
@JúlioTurollaRibeiro "Do you think Apple will create something easier" is a subjective question. If the information isn't out there, no one can answer that for you. So it's not a constructive thing to ask.Mineral
I suppose they have made something easier by introducing the new relative layout system, sadly it's no use if you want to support < ios6. This solution is good for me though. Thanks @tomaszGeneratrix
E
3

As it has more pixels in height, things like GCRectMake that use coordinates won't work seamlessly between versions, as it happened when we got the Retina.

Well, they do work the same with Retina displays - it's just that 1 unit in the CoreGraphics coordinate system will correspond to 2 physical pixels, but you don't/didn't have to do anything, the logic stayed the same. (Have you actually tried to run one of your non-retina apps on a retina iPhone, ever?)

For the actual question: that's why you shouldn't use explicit CGRectMakes and co... That's why you have stuff like [[UIScreen mainScreen] applicationFrame].

Euglena answered 12/9, 2012 at 21:45 Comment(8)
"as it happened when we got the Retina." -> I know they do work between Retina/Non retina, sorry if I wasn't clear. I'm saying that this seamless conversion won't work in the iPhone 5.Psephology
Don't you think apple will make something easier than having to programatically check the size of the screen?Psephology
Yes Robert! Well, things like that worked till now...Psephology
@JúlioTurollaRibeiro easier? You mean that Apple with create some tool with crystal ball to change code full of magic constants, which does work only by coincidence (= still same screen dimension till today)?Palatinate
@RobertVojta CGRectMake(0, 0, 320, 480); does work on Retina displays just like it works on non-retina ones.Euglena
@H2CO3 yeah, but OP is talking about iPhone 5, which is taller and have different screen dimension. So, it's wrong code, because it doesn't respect bounds (unless you do want really this size). Otherwise (bounds respected) means no code change.Palatinate
Well, maybe! :) Apps that have a tableview, for instance, can just strech it. They can create an conditional stretching, anything! I trust them in making good programming tools besides great products.Psephology
@RobertVojta I'm aware of this :) But I wanted to clear up the misbelief he had. Of course, the above code will break on the iPhone 5's taller screen. (I know it's taller - I've been liveblogging the keynote ;-)Euglena

© 2022 - 2024 — McMap. All rights reserved.