Tag Archives: iPad

How to load a different storyboard for different iPad Sizes

Since the introduction of the iPad Pro range, we now have to deal with three distinct iPad screen sizes. And although the 10.5″ and 9.7″ are very similar in size, the giant iPad Pro 12.9″ easily looks shockingly bad when used with a storyboard that otherwise looks handsome on the “smaller” iPad screens.

So what is a dev to do? Prepare a completely different storyboard for an iPad Pro 12.9″ of course! I’ve shown in the past how to do this for different phone sizes, so here’s how to do it for different iPad sizes. This approach will work with iOS 8 and above.

Determining the Screen Height

Sadly Apple have not implemented a new UIUserInterfaceIdiom property we could question. Every iPad device will only identify itself as an iPad rather than an iPad Pro model. But I guess this wouldn’t help us much anyway, since we have three screen sizes as of 2017, with god only knows how many more in the pipeline.

Hence, we need to determine what screen height we’re dealing with. To do this reliably though, we must also know if the user is holding the device in portrait or landscape mode when our app starts, otherwise “height” might be interpreted differently.

Lucky for us, there is a trait collection property we can use to question this, called fixedCoordinateSpace. We can call it on our UIScreen class. Here’s how:

int height = [UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height;
NSLog(@"The fixed height is %i", height);

This test shall be at the heart of our endeavours. When derived like this, height will always deliver the “portrait up” height of our device, regardless if the app starts in portrait or landscape mode.

Now we’ll add another test to it, namely if the device we’re testing is in fact an iPad. If it is, we’ll compare the height parameter to the height of a 10.5″ iPad (which is 1024 pixels, just like it would be for a 9.7″ device). If it’s larger, we’re dealing with a 12.9″ device. And if it’s not an iPad at all, we’ll load an iPhone storyboard.

Here’s how we might do that:

- (UIStoryboard *)grabStoryboard {

    UIStoryboard *storyboard;
    
    // detect screen height
    int height = [UIScreen mainScreen].fixedCoordinateSpace.bounds.size.height;
    NSLog(@"The fixed height is %i", height);
    
    // determine if this is an iPad
    if (UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad) {
        
        // it's an iPad 10.5" or lower
        if (height <= 1024) {
            
            storyboard = [UIStoryboard storyboardWithName:@"iPad" bundle:nil];
        } else {
            // it's an iPad Pro 12.9"
            storyboard = [UIStoryboard storyboardWithName:@"iPad-Pro" bundle:nil];
        }
        
    } else {
        // not an iPad, load regular storyboard
        storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    }
    
    return  storyboard;
}

In our project we have three storyboards: Main, iPad and iPad-Pro. Each of these will now be returned by this method depending on their screen height.

Displaying our Storyboard

Now that we have a reference to the one we need, let’s load it in our AppDelegate. We’ll do that just before returning YES in the didFinishLaunchingWithOptons method:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // grab and show the storyboard
    UIStoryboard *storyboard = [self grabStoryboard];
    self.window.rootViewController = [storyboard instantiateInitialViewController];
    [self.window makeKeyAndVisible];
    
    return YES;
}

It is irrelevant which storyboard is set as the main storyboard in the iOS target, it will be overridden by this method’s last two calls.

Demo Project

I’ve got a demo project on GitHub to demonstrate this, feel free to check it out and tinker with it:





How to add your own shortcuts above the keyboard in iOS 9

Photo-23-10-2015,-17-44-21

Ever wondered how to create those new shortcut items that can appear above the iPad keyboard in iOS 9?

By default iOS will produce auto correction suggestions here since iOS 8, but since iOS 9 we can hook into this mechanism and provide our own bar button items on the left and right – much like we can with a navigation bar.

Let me show you how to do it.

UIBarButtonItems and the UITextInputAssistantItem

In the above screenshot we can see an icon at the left, and a single shortcut on the right. Those are instances of our old friend the UIBarButtonItem. In short, each item is added to an array, and each button in the array is displayed – if iOS has the space above the keyboard.

Apple doesn’t seem to have a name for this space, but the class that’s responsible for showing those shortcuts is called the UITextInputAssistantItem. There’s room for a leading and a trailing group of items.

This group isn’t just an array of buttons though; it’s another class called the UIBarButtonItemGroup, and the clever bit is that this group has a representative “action button” that is shown and will open the group if there’s not enough space. I know this sounds complicated, but bear with me here.

In the screenshot above, on the left hand side, we can see an “action button” (literally). iOS shows this because there’s not enough room to display the words “First Shortcut” and “Second Shortcut”. But when we press it, we’ll see something like this:

Photo-23-10-2015,-18-03-36

On the right hand side, the shortcut titles are short enough to be displayed and this representative button isn’t shown – however we still need to define one in case that space is getting tight.

Let’s see how to do this in code.

Continue reading





How to create Popovers in iOS 9

Screen Shot 2015-10-18 at 08.55.13

iOS 8 introduced a new way of creating Popovers on iPad: instead of using the trusty old (nightmarish) UIPopoverController class, we can now use the UIPopoverPresentationController. It’s available on iPads as well as iPhones.

The great news for us developers is that we no longer have to check what type of device we’re on and present our content accordingly:  we simply present a Popover, and if we happen to be on an iPhone, iOS will automatically show our view controller as an action sheet instead. No other code change or if-then query is necessary.

While this approach was optional in iOS 8, the UIPopoverController is now deprecated and should no longer be used in iOS 9 (and good riddens I say). Both the creation as well as dismissal process have been streamlined, and I find it’s now actually a joy rather than a chore to play with Popovers.

Let’s see how to create a simple Popover Presentation Controller in iOS 9.
Continue reading





How to convert your iPhone Storyboard into an iPad Storyboard

Sometimes it’s just easier to start from an existing Storyboard rather than build everything again from scratch. Especially so when you want to create an iPad version of your iPhone app.

When you change your deployment info to Universal, Xcode even offers to copy your existing storyboard for you. That’s really nice – but even though it behaves like an iPad storyboard, when you open it in Interface Builder it still looks like you’re creating an iPhone layout. This makes re-arranging things difficult.

Help it at hand with a simple tweak. Under the hood, a Storyboard is just an XML file and as such as a plethora of key/value pairs we can change by hand.

First, make sure you display your layouts in “3.5inch” mode. You can do that by clicking that little icon at the bottom of Interface Builder:

Screen Shot 2014-05-19 at 11.20.25

Next head over to the File Inspector and right-click your storyboard, then select “Open as Source Code”. This will display all that XML code.

Screen Shot 2014-05-19 at 11.08.32

In the second line of the document you’ll find a very long line – somewhere in it you’ll find something like this:

targetRuntime="iOS.CocoaTouch"

Simply change that line to

targetRuntime="iOS.CocoaTouch.iPad"

This will make Interface Builder display your storyboard with iPad characteristics. All we now have to do is to make it look like a Storyboard again rather than XML code – so head back and right-click on the file again, then select “Open as Interface Builder – iOS Storyboard”.





How to support iPad 1 rotation in Xcode 5

I was very excited when an old iPad 1 was delivered to me today – in marvellous condition! It will allow me to test my apps against iOS 5.1.1.

I immediately noticed that all Xcode 5 templates no longer have the rotation code embedded – without which iPad 1 won’t auto rotate.

Here’s what you need to implement into your UIViewController sub classes to support auto rotation:

// support auto rotation in iOS 5
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	return YES;
}

Note than when you’re using the Master/Detail Template or any Split View Controller app you need to implement the above method in BOTH view controllers. Don’t ask me why – I’m just the messenger.

If you have an app based on a tab bar controller which houses several other view controllers, it’s enough to add this statement once to the initial view controller to make rotation work on all other view controllers. So the view controller currently “in vision” needs to have the above statement added.





How to show the Master View button in a UISplitViewController app

I was tinkering with an iPad version of one of my apps, when I noticed that the nav bar button that hides and shows the Master View Controller in portrait mode was no longer displayed. You know, the one that reads “Master” by default.

This is a problem if my app starts in portrait mode, because there’s no way to bring this button back. The Split View Controller handles that button in its willHideViewController delegate method – which was seemingly never called upon startup (anymore).

I can’t call that method manually on startup because I don’t have the parameters that call this method – but I did find a solution that forces the Split View to call this method:

// bring back the Master button in portrait
[self.splitViewController.view setNeedsLayout];

Calling this somewhere in viewDidLoad doesn’t hurt your app – but it avoids having to solve The Case of the Disappearing Split View Button.