You are on page 1of 20

iPad and Universal (iPhone + iPad) Apps

Building MonoTouch Applications that run on both the iPad and iPhone Getting Started Tutorial 5

Xamarin Inc.

BRIEF
This is the final tutorial in the Getting Started with MonoTouch series. It walks through creating an iPad application, and then examines how universal applications can be created that are designed to work with both the iPad and the iPhone. Next, it walks through creating a universal application using the Universal Application Project Template, and finally, it introduces a customization to the template that allows more complex applications to be targeted to both devices. Sample Code: Hello, iPad Hello, Universal Hello, Complex Universal Related Articles: Getting Started Tutorial 4 - Intro to MVC in iOS

Overview
Weve covered a lot of ground so far in these Getting Started tutorials. So far, weve introduced the toolset, building and deploying applications, Outlets and Actions, and the MVC pattern. However, everything that weve done has all been iPhone/iPod Touch based. In this final tutorial in the Getting Started series, were going to walk through creating an iPad application, then, were going to walk through creating a universal application that runs equally well on both the iPhone and the iPad The following are screenshots of one of the first universal application were going to build:

Requirements
This tutorial builds on the concepts introduced in the previous Getting Started tutorials. Therefore, its highly recommended that you complete Getting Started tutorials 1-4 before beginning this one.

Building for iPad


From an application perspective, building for the iPad is nearly the same process as building for the iPhone. Everything that weve learned thus far in these tutorials applies to iPad applications. The MVC Pattern still applies, and although there are a couple of additional iPad-only controls, the rest of the UIKit still applies, too. The main difference between iPhone applications and iPad applications is in designing the UI, because the iPad presents a much larger form factor; its nearly the size of a common sheet of paper. Having this much screen real estate means that functionality that might be split across several screens in the iPhone can fit on a single screen in the iPad. For instance, lets look at the Settings Application in the iPhone:

The same functionality is collapsed into fewer screens in the iPad:

In fact, with all that screen space, you could easily imagine how the Settings Application could be collapsed further. This is the reason that there are additional controls for the iPad. In the above screenshot, the Settings Application uses the split view controller, which is only available on the iPad. OK, lets take a look at actually creating an iPad application.

Creating our iPad Application


Open up MonoDevelop (MD) and create a new solution. In the New Solution dialog, select C# : MonoTouch : iPad. Youll notice that all the iPhone templates also have a corresponding iPad template:

Were going to make a very simple application, so choose MonoTouch Single View Application iPad and name it Hello_iPad. The resulting project looks nearly identical to the Hello, iPhone application we created in an earlier Getting Started tutorial:

Project Options
In fact, the only real difference is in our .plist file. If we right-click on the project, and choose Options, well see that the Devices setting is set to iPad:

By changing Devices setting to iPad, the dialogue also gives options specific to the device.

Interface Builder and iPad Views


Editing iPad .xib files in Interface Builder (IB), is exactly like editing iPhone .xib files, except the designer is much larger. Double-click on the Hello_iPadViewController.xib and itll open up in IB:

Lets add a label to the view, and save it:

We dont need any Outlets or Actions, but adding them is the same process as it is for the iPhone you open the Assistant Editor, and Control-drag from the control to the .h file.

Running an iPad App


Now lets build and run our iPad app. If we look at the Project menu > iPhone Simulator Target, its set to Default, but since weve set the Device to be an iPad in the .plist file, the iOS Simulator will open up and simulate the iPad, which looks nearly the same as the iPhone Simulator, except for the size:

Thats it! Weve built our first MonoTouch iPad application!

iPad Icons
iPad application icons are specified in the Info.plist file, just like iPhone application icons are. The only difference is the size needed for them. The following table lists the icons and sizes needed for iPad applications: Icon Use Application Icon Size for iPad (in pixels) 72x72

Spotlight and Settings

Spotlight: 50x50 Settings: 29x29

App Store Icon (only needed if publishing on App Store)

512x512

To add these icons, follow the same procedure we did for the Hello, iPhone application: right-click on the project and choose Add : Add Files. To configure these icons, either double-click on the Info.plist file in the Project Navigator, or double-click on the project and choose iPhone Application in the Options dialog.

iPad Default Loading Screens


Specifying a loading screen in iPad is conceptually the same as with iPhone apps, you just move your properly named and sized images into the project root, and iOS will automatically show them during application launch. However, things are slightly more complicated in iPad apps because instead of two images (as there are for the iPhone), you can optionally specify up to four; one for each orientation. Additionally, unlike the iPhone, the status bar is viewable when an iPad application launches, which means that you must take into account that 20 pixels at the top of the screen are already occupied. This is also dependent on orientation, because the status bar is always at the top. So, if the iPad is in portrait mode, the loading image needs to be 768x1004 pixels, and if in landscape, it needs to be 1024x748 pixels. The following table lists the types of iPad loading images, as well as their sizes (width x height) and orientations. The images are listed in order of precedence; images further down the list take precedent over images higher in the list: File Name Size (in Use pixels) 768x1004 This is the basic loading image that is used if a more specific image is not available. If no more specific images are supplied, this should be present. This is the generic portrait loading image. This image is used for right-side up (home button on bottom) portrait orientations and takes precedence over Default~ipad.png. Therefore, if you supply this image, Default~ipad.png is not used. Additionally, if DefaultPortraitUpsideDown~ipad.png is not supplied, this image is used. This is the generic landscape loading image. This image takes precedence over Default~ipad.png. Therefore, if you supply this image, Default~ipad.png is not used. Additionally, if DefaultLandscapeLeft~ipad.png or DefaultLandscapeRight~ipad.png is not supplied, this image is used. This is the portrait upside-down (home button on top) loading image.

Default~ipad.png

Default-Portrait~ipad.png

768x1004

Default-Landscape~ipad.png

1024x748

Default-PortraitUpsideDown~ipad.png

768x1004

Default-LandscapeLeft~ipad.png

1024x748

This is the landscape left (home button on left) loading image. This is the landscape-right (home button on right) loading image.

Default-LandscapeRight~ipad.png

1024x748

Unless you want to have different images for each orientation, you only need to supply a Default~ipad.png image if your application only supports portrait mode. If your app only supports landscape orientation, you only need the Default-Landscape~ipad.png image. If you support both landscape and portrait orientation, then you should supply at least these two images. This significantly reduces the amount of images you must create, since supplying one for every orientation is typically overkill. For more information about loading images, see the Apple documentation on Custom Icon and Image Creation Guidelines. OK, now that weve covered iPad applications, lets take a look at how to build apps that target both the iPhone and iPad.

Universal Applications
Universal iOS applications are applications that will load the appropriate UI, depending on which device they run on. For instance, you might have one UI defined for the iPhone, and another UI defined for the iPad. A universal application will automatically load the correct UI. This is typically accomplished when the FinishedLaunching method of your application delegate detects which device is running, and then launches the appropriate UI. Fortunately for us, MonoDevelop ships with a universal project template that contains the basic code to accomplish this. Lets take a look at it.

Universal Project Template


Lets create a new solution, this time well choose C# : MonoTouch : Universal : MonoTouch Single View Application Universal:

Lets name the project Hello_Universal. If you take a look at the project structure created from this template, youll notice something a little different. There is one view controller, but two associated .xib files:

PROGRAMMATIC DEVICE DETECTION


To understand how this works, lets take a look at the FinishedLaunching method in the AppDelegate class (found in AppDelegate.cs):
public override bool FinishedLaunching (UIApplication app, NSDictionary options) { // create a new window instance based on the screen size window = new UIWindow (UIScreen.MainScreen.Bounds); if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) { viewController = new Hello_UniversalViewController ("Hello_UniversalViewController_iPhone", null); } else { viewController = new Hello_UniversalViewController ("Hello_UniversalViewController_iPad", null); } window.RootViewController = viewController; window.MakeKeyAndVisible (); return true; }

The magic here begins with this line:


if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) {

The UIDevice.CurrentDevice object exposes a property called UserInterfaceIdiom that returns a UIUserInterfaceIdiom enumeration that lets us know what the current device is. There are two possible values for this enumeration: Pad and Phone, corresponding to the iPad and iPhone/iPod Touch, respectively. Once weve determined which device is running the application, then we instantiate our view controller, and pass the appropriate .xib name to instantiate:
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) { viewController = new Hello_UniversalViewController ("Hello_UniversalViewController_iPhone", null); } else { viewController = new Hello_UniversalViewController

("Hello_UniversalViewController_iPad", null); }

This works, because if we look at the controller constructor, we see the following:
public Hello_UniversalViewController (string nibName, NSBundle bundle) : base (nibName, bundle)

The base class will load the .xib file based on the name (recall from Getting Started tutorial 3 that Nib is another name for .xib files). In this case, were passing either Hello_UniversalViewController_iPhone, or Hello_UniversalViewController_iPad, depending on the device.

CREATING THE USER INTERFACE


So far, so good, but lets actually put this in action. First, lets open the Hello_UniversalViewController_iPad.xib file in Xcode and add a couple of labels and a button:

Were going to update the bottom label with some text when the button is clicked, so make sure its fairly wide, so that the text doesnt get truncated. Next, well do the same thing with the Hello_UniversalViewController_iPhone.xib file:

Again, be sure to make the bottom label fairly wide so the text doesnt get truncated.

SHARING OUTLETS AND ACTIONS ACROSS MULTIPLE VIEWS


So now we have two views that share the same controller, but how do we create Outlets and Actions that work across the two views? Well, it turns out that this is very similar to how Actions are shared. Lets first create our Outlets. Open up the iPhone view and the corresponding shared controller .h file in Xcode and Control-drag to create the following outlets: btnClickMe lblOutput The btnClickMe outlet should be wired to the button, and the lblOutput should be wired to the lower label. When were done we should have something like this:

Our .h file should have the following Outlet code:


@property (nonatomic, retain) IBOutlet UIButton *btnClickMe; @property (nonatomic, retain) IBOutlet UILabel *lblOutput;

Next, lets open up the iPad view. This time, were going to Control-drag to the existing Outlets that we created when the iPhone view was open:

Now our Outlets are shared across the two .xib files. Lets save our work and switch back over to MonoDevelop. We can now use the same Outlets in the same ways, whether the app is running on an iPhone or an iPad. Lets modify our Hello_UniversalViewController classs ViewDidLoad method to see this in action:
public override void ViewDidLoad () { base.ViewDidLoad (); this.btnClickMe.TouchUpInside += (sender, e) => { this.lblOutput.Text = "Clicked @ " +

DateTime.Now.ToShortTimeString(); }; }

Now, when we run it and click the button, we should see something like this:

Notice that the iPhone simulator launches by default. We can force the application to run in the iPad simulator by selecting iPad Simulator 4.3 from the Project > iPhone Simulator Target menu. When we run the application now, it will launch in the iPad simulator, and when we click the button, the code will run just as it did when we used the iPhone simulator:

Complex Universal Applications


The approach weve used so far, where a single controller manages two different views based on the device, works fine for simple screens in which there are the same Outlets, Actions and user interactions between the iPhone screen and the iPad screen, but this is a rare occurrence in the real world. Typically, iPad apps and iPhone apps differ substantially in terms of UI and user interaction (referred to as User eXperience [UX] when taken together). For example, consider the following two different interfaces for the same app on different devices:

In this case, wed want to have two different controllers because the Outlets would be different. This is obviously a contrived UI, but you can imagine that in some applications the UI is drastically different between devices. To load a different controller depending on the device, the first thing that we should do is to declare a generic UIViewController in our AppDelegate class, rather than a specific one (say homeScreen_iPad or homeScreen_iPhone):
public partial class AppDelegate : UIApplicationDelegate { // class-level declarations UIWindow window; UIViewController homeScreen; }

Then, in the FinishedLaunching method, when we determine which device is in use, we load the appropriate controller, and then set that controller as our root:
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) { homeScreen = new Screens.HomeScreen_iPhone(); } else { homeScreen = new Screens.HomeScreen_iPad(); } window.RootViewController = homeScreen;

Now, when we run the application, the correct controller for the device will be shown.

Summary
Congratulations, this was the final tutorial in the Getting Started series! In this tutorial we learned how to create an iPad-only application, as well as two different approaches to creating universal applications. If youve been going through these tutorials from start to finish, youre now well on your way to becoming a proficient MonoTouch iOS developer!

You might also like