How to load UIStoryboards depending on screen height in iOS

A while ago I’ve written an article about how to load different storyboards depending on the screen size of an iOS device. Back in those days (2013) it was all a bit simpler than it is today, and I looked into it mainly because I loathed Auto Layout so much.

I felt it was time for an update, so here it is!

Things haven’t gotten any easier in iOS, because currently we have the following 5 screen sizes to deal with:

  • iPhone 6 Plus: 736×414 @3x
  • iPhone 6: 667×375 @3x
  • iPhone 5s: 568×320 @2x
  • iPhone 4s: 480×320 @2x
  • all iPads: 1024×768 @1x / @2x

It’s very difficult to make a UI look nice on all devices with a single UIStoryboard, and in the above video I’m showing you an alternative: design a completely different storyboard for each screen size.

The upkeep of such an app will be a little more complex, but it puts us in full control of the user experience, and not some compromise that sounds good in the Apple presentation (and sucks in reality).

In principle, the following steps are involved:

  • design various storyboards
  • detect the current device’s screen height
  • load the appropriate storyboard
  • make it “key and visible”

Detecting the screen size

If your app is set to “auto-rotate” (i.e. both portrait and landscape modes, or portrait only), the screen height will detect the longer side of the screen. This is true even if the app is started in landscape mode. Determining screen height can be done like this:

int screenHeight = [UIScreen mainScreen].bounds.size.height;
NSLog(@"Screen Height is %i", screenHeight);

Note that if you set your app to “landscape only” mode, the height parameter will return the shorter side of the screen – in which case, bounds.size.width to determine the longer portion of the screen. Thanks to Johan Grip for bringing this to my attention!

iOS 7 compatibility

Note that the screen size is orientation dependant since iOS 8 – previous versions did not take this into a account. If you must support iOS 7 and earlier it gets a lot more complicated (and I won’t cover this here – sorry).

However, this Stack Overflow discussion may help you in that case: http://stackoverflow.com/questions/24150359/is-uiscreen-mainscreen-bounds-size-becoming-orientation-dependent-in-ios8

Loading the correct UIStoryboard

With this handy integer in place, we can build a switch statement to react according to the screen height. I’m using the following method that returns my desired storyboard in my AppDelegate implementation file.

If you’re not worried about each single size, feel free to write a shorter if/then/else type method.

 

- (UIStoryboard *)grabStoryboard {
    
    // determine screen size
    int screenHeight = [UIScreen mainScreen].bounds.size.height;
    UIStoryboard *storyboard;
    
    switch (screenHeight) {
            
            // iPhone 4s
        case 480:
            storyboard = [UIStoryboard storyboardWithName:@"Main-4s" bundle:nil];
            break;
            
            // iPhone 5s
            case 568:
            storyboard = [UIStoryboard storyboardWithName:@"Main-5s" bundle:nil];
            break;
            
            // iPhone 6
            case 667:
            storyboard = [UIStoryboard storyboardWithName:@"Main-6" bundle:nil];
            break;
            
            // iPhone 6 Plus
            case 736:
            storyboard = [UIStoryboard storyboardWithName:@"Main-6-Plus" bundle:nil];
            break;
            
        default:
            // it's an iPad
            storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
            break;
    }
    
    return storyboard;
}

 

Displaying the storyboard

Inside our AppDelegate method didFinishLaunchingWithOptions, we’ll call the above method and grab the storyboard we need. To make it show up, we need to load it as the window’s root view controller and declare it “key and visible”. This is akin to the old-style way of making things appear on our iOS screens.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // grab correct storyboard depending on screen height
    UIStoryboard *storyboard = [self grabStoryboard];
    
    // display storyboard
    self.window.rootViewController = [storyboard instantiateInitialViewController];
    [self.window makeKeyAndVisible];
    
    return YES;
}

Note that using this approach will override whatever storyboard is declared in your target (under General – Deployment Info – Main Interface).

 

Demo Project

I’ve updated this project on GitHub, it shows exactly what I’m building in the screencast. Play and enjoy 🙂





14 thoughts on “How to load UIStoryboards depending on screen height in iOS

    1. Hi Marto,

      sadly I don’t know Swift and haven’t had a chance to learn it yet. I was told by a YouTube commenter that the principle does work fine in Swift, but I haven’t got any code to share. All the best!

  1. Brilliant, thanks! I only needed to worry about 3.5-inch screen, so Swift code is:

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    	// Override point for customization after application launch.
    
    	// grab correct storyboard depending on screen height
    	let properStoryboard = self.chooseStoryboard()
    
    	// display storyboard
    	self.window!.rootViewController = properStoryboard.instantiateInitialViewController()
    	self.window!.makeKeyAndVisible()
    
    	return true
    }
    
    func chooseStoryboard()->UIStoryboard {
    	// determine screen size
    	let screenHeight = UIScreen.mainScreen().bounds.size.height
    	var storyboard: UIStoryboard
    
    	if (screenHeight == 480) {
    		storyboard = UIStoryboard(name: "iphone4s", bundle:nil)
    	}
    
    	else {
    		storyboard = UIStoryboard(name:"Main", bundle:nil)
    	}
    
    	return storyboard;
    }
    
  2. i need to load different storyboard using Autolayout for IPad portrait and IPad landscape.
    i am using Autolayout now but i am not able to handle my ui design for both the landscape and portrait. your any suggestion would be highly appreciated. please any one help. Thanks in advance.

      1. Hello Jay Versluis, Thanks for an update. i am using Width Regular & Height Regular Size Classes in iOS 9 using Autolayout and i need to load different storyboard for IPad Landscape & IPad Portrait only for three ViewController and my other screen are working fine in both the orientation. so i would your any suggestion what should i do for these three ViewController. Thanks

        1. You can use the technique I’ve described for each individual view controller that needs it. Implement the block in each of your view controllers as described, check the rotation of the device, and then load a different storyboard at that moment.

          1. Hi Versluis Thanks for an update i am new in ios development can you grab the code here that i need to implement to load different storyboard for IPad Landscape & IPad Portrait using auolayout. Thanks

  3. Hi Versluis, Thanks alot for the source code. it works like a charm But when we have more then one ViewController then during rotation it comes back to the initial ViewController.
    it is not working when it is not set to the initial ViewController. Please help Thanks.

    1. Hi yash,

      Instantiate a different view controller from your storyboard then, instead of the initial one. In the storyboard, head over to the Identity Inspector and give your view controller a Storyboard ID. Then use the following to instantiate it:

      // instantiate a specific view controller with ID
      self.window.rootViewController = [storyboard instantiateViewControllerWithIdentifier:@"YourID"];
      [self.window makeKeyAndVisible];
      

Leave a Reply