42

Trying to make my app work with both iPhone 5 and iPhone 4/4s. I tried the "AutoLayout" but does not seem to work for my app also read that it is not supported in iOS 5. AutoLayout specifically fails on a view controller that has an UIScrollview and a UIPicker that is re-sized in code. Having two Storyboards one for 4 inch and one for 3.5 inch seems the way to go.

The two Storyboard aproch seem to be the solution for me. So this leaves me with two questions;

  1. Where should the code to detect then if it is a 4/4s/5 go? I would assume in the appDelegate.m in the didFinishLaunchingWithOptions method

  2. How do I change the "Main Storyboard"?

Xaphann
  • 3,195
  • 10
  • 42
  • 70
  • You should also consider using springs and struts to resize your view instead of duplicating your storyboard, especially if all that is changing is the layout. It could easily lead to a much more maintainable solution, and will support previous releases of iOS. – Jon Hess Sep 21 '12 at 21:32
  • Using the answers provided, I created a category to make this easier -- https://gist.github.com/4003438 – James Sumners Nov 02 '12 at 18:47
  • couldn't be easier ... http://stackoverflow.com/a/13040627/294884 or http://stackoverflow.com/a/12799462/294884 – Fattie Sep 16 '14 at 09:20

5 Answers5

60

This is a great question.

What you need to do is,

  1. Select your current 4/4s storyboard, go to File, duplicate, then give it an iPhone 5 specific name. Make sure that Target and your app name is checked.

  2. Next you have to select the scenes in your storyboard and in the Attributes Inspector change the size to Retina 4 Full Screen. This allows you to rearrange everything for this display.

  3. Finally in application didFinishLaunchingWithOptions paste the following code with the storyboard name you gave for your 4 inch storyboard.

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
        UIStoryboard *storyBoard;
    
        CGSize result = [[UIScreen mainScreen] bounds].size;
        CGFloat scale = [UIScreen mainScreen].scale;
        result = CGSizeMake(result.width * scale, result.height * scale);
    
        if(result.height == 1136){
            storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone_5" bundle:nil];
            UIViewController *initViewController = [storyBoard instantiateInitialViewController];
            [self.window setRootViewController:initViewController];
        }
    }
    
    return YES;
    }
    

If anyone don't get how to do step 1, do as below.

  1. Go to Project directory and copy paste the MainStoryboard.storyboard and rename new storyboard to say MainStoryboard5.storyboard.

  2. Add this new storyboard MainStoryboard5.storyboard in project (in Xcode) by right clicking Project and clicking Add Files to ....

  3. Now we have two storyboards in xcode.

Tip

You may have to use 'Product > Clean' for this to work after you have done all the above.

ErikE
  • 48,881
  • 23
  • 151
  • 196
fields.cage
  • 1,643
  • 12
  • 8
  • Thanks. Make sure that you have added you splash screen before you run the project :) – BigAppleBump Dec 10 '12 at 19:05
  • I developed another app recently and built everything with the 4" display in storyboards. When running it on the 3.5" displays everything will adjust to that display if you have your UI elements anchored correctly. There was a background image that I had to write an if statement in a class' viewDidLoad that checked the height of the screen using the code above. This changed which image appeared according to the current device to ensure the picture would not look squished when displayed on 3.5" screens. – fields.cage Dec 11 '12 at 19:55
  • 1
    You can duplicate the storyboard by click on File->Duplicate(Command+Shift+S) and then rename it like "storyboard_iPad.storyboard",,, don't forget the ".storyboard" extension – MohamMad Salah Dec 15 '12 at 13:46
  • @fields.cage i have make what you are say exactly but my project appear on simulator not exactly what i do in iphone5 stoaryboard and i check every thing – khaled Feb 06 '13 at 15:14
  • When I add the code I receive an error stating Property 'window'not found on object of type 'ViewController*' – flyers Mar 27 '13 at 17:04
  • Are you adding this code to a ViewController or the AppDelegate.m file? – fields.cage Mar 28 '13 at 18:20
  • This does not work in iOS 8 with Xcode 6, does anybody know how to make it work with it? – msweet168 Nov 23 '14 at 07:41
7

Currently the only way is to check if you're using the iPhone 5 is the [UIScreen mainScreen] bounds] and [[UIScreen mainScreen] scale].

BOOL isIphone5 = (([[UIDevice currentDevice] userInterfaceIdiom] 
== UIUserInterfaceIdiomPhone) && (([UIScreen mainScreen].bounds.size.height * 
[[UIScreen mainScreen] scale]) >= 1136));

This only works if you have at least added a Default-568h@2x.png launch image to your application. Else this will always return false. (Because the screen will be letterboxed if you don't have the launch image)

To set the storyboard to your iPhone 5 version you might want to take a look at this question

Community
  • 1
  • 1
Leon Lucardie
  • 9,541
  • 4
  • 50
  • 70
2

I took inspiration on fields.cage answer and adapted it to my code, it works fine. Thanks !!

if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
        UIStoryboard *storyBoard;

        CGSize result = [[UIScreen mainScreen] bounds].size;
        CGFloat scale = [UIScreen mainScreen].scale;
        result = CGSizeMake(result.width * scale, result.height * scale);

        if(result.height == 1136){


             self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPhone5" bundle:nil] autorelease];

        }
        else
        {
             self.viewController = [[[ViewController alloc] initWithNibName:@"ViewController_iPhone" bundle:nil] autorelease];
        }
    }
Tanos
  • 49
  • 8
1

What i have been doing recently is adding a define statement in any classes i need to check the device. This can also be done in any global header files.

#define IS_IPHONE (!IS_IPAD)
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone)

The bool test is from Detect iphone 5 4" screen.

bool isiPhone5 = CGSizeEqualToSize([[UIScreen mainScreen] preferredMode].size,CGSizeMake(640, 1136));
if (isiPhone5) {
        // Setup For iPhone 5 Screen Size
    UIStoryboard *storyBoard;

    storyBoard = [UIStoryboard storyboardWithName:@"MyiPhone5StoryboardName" bundle:nil];
    UIViewController *initViewController = [storyBoard instantiateInitialViewController];
    [self.window setRootViewController:initViewController];
}

This works beautifully if you are already using storyboards, and only want to change the storyboard from the defaults that your project started with for iPhone 5 devices. If you are starting from scratch with an existing non-Storyboard project you can do it this way.

#define IS_IPHONE (!IS_IPAD)
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone)

bool isiPhone5 = CGSizeEqualToSize([[UIScreen mainScreen] preferredMode].size,CGSizeMake(640, 1136));
if (isiPhone5) {
        // Load iPhone 5 Storyboard
    UIStoryboard *storyBoard;

    storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone5" bundle:nil];
    UIViewController *initViewController = [storyBoard instantiateInitialViewController];
    [self.window setRootViewController:initViewController]; 
}

else if (IS_IPAD) {
        // Load IPAD StoryBoard
    UIStoryboard *storyBoard;

    storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPad" bundle:nil];
    UIViewController *initViewController = [storyBoard instantiateInitialViewController];
    [self.window setRootViewController:initViewController]; 
}

else {
        // Load the iPhone 3.5" storyboard
    UIStoryboard *storyBoard;

    storyBoard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil];
    UIViewController *initViewController = [storyBoard instantiateInitialViewController];
    [self.window setRootViewController:initViewController]; 
}

When i start a project now i design the iPhone 3.5" version in storyboards (If i am using storyboards), then when i am done with that design i go into my project files and find the storyboard file. Since a storyboard file is just an XML layout file, i can take that file and load it in my favorite text editor and change two tags.

Convert iPhone to iPad

  1. At the top of the file find targetRuntime="iOS.CocoaTouch"
  2. Change to targetRuntime="iOS.CocoaTouch.iPad"
  3. Ad the bottom of the file you may find this <simulatedScreenMetrics key="destination" type="retina4"/>
  4. Change this to <simulatedScreenMetrics key="destination"/>

The last item will only appear if the your main storyboard file is setup for the 4" iPhone screen.

What is important here is if your only adding iPhone 5 to an existing project you only need the first check to override the default, and load your special storyboard file. This literally saved me from having to manually layout all objects in code for iPhone 5.

Community
  • 1
  • 1
Nelson Brian
  • 688
  • 6
  • 7
0

The first one Work very good is simple and clear, but for all if you want to integrate multiply devices look here:

  1. Create a project for iPhone5 with a Storyboard named iPhone5_Storyboard.

  2. Close app and inside a folder clone the Main Story called iPhone5_Storyboard and rename in to iPhone4_Storyboard not forget to change size and reorder all object inside xcode interface builder.

  3. Optional if you want a Universal version, inside xcode use Add File and adding new Storyboard EMPTY target for iPad, ope un iphone5_storyboard use CMD+A and copy all and paste in the Empty Story for iPad (need to reorder object, but is all linked and working).

  4. In Xcode under TARGET set Universal App and setting under MainStoryboard you iPhone5_Storyboard, under iPad Main Story setting iPad_Storyboard.

  5. Now THANKS TO A FIRST ANSWER OF THIS POST we have to implement all different Story using this code inside a AppDelegate.m:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
        UIStoryboard *storyBoard;

        CGSize result = [[UIScreen mainScreen] bounds].size;
        CGFloat scale = [UIScreen mainScreen].scale;
        result = CGSizeMake(result.width *scale, result.height *scale);

//----------------HERE WE SETUP FOR IPHONE4/4s/iPod----------------------

        if(result.height == 960){
            storyBoard = [UIStoryboard storyboardWithName:@"iPhone4_Storyboard" bundle:nil];
            UIViewController *initViewController = [storyBoard instantiateInitialViewController];
            [self.window setRootViewController:initViewController];
        }

//----------------HERE WE SETUP FOR IPHONE3/3s/iPod----------------------

        if(result.height == 480){
            storyBoard = [UIStoryboard storyboardWithName:@"iPhone4_Storyboard" bundle:nil];
            UIViewController *initViewController = [storyBoard instantiateInitialViewController];
            [self.window setRootViewController:initViewController];
        }
    }

        return YES;
 }

That's it now we have a universal App for iPhone 3/3Gs/4/4s/5 iPod (AllGen) iPad 1/2/3/4 Mini and Retina

Thanks guys

BlackSheep
  • 1,087
  • 12
  • 29