Table of contentsBuilding MonoTouch Applications that run on both the iPad and iPhone
Getting Started - Tutorial 5 BriefThis is 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. Time to Complete: 1.5 Hours Sample Code: PDF Version for Offline Use Related Articles: OverviewWe’ve covered a lot of ground so far in these Getting Started tutorials. So far, we’ve introduced the toolset, building and deploying applications, Outlets and Actions, and the MVC pattern. However, everything that we’ve done has all been iPhone/iPod Touch based. In this final tutorial in the Getting Started series, we’re going to walk through creating an iPad application, then, we’re 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 we’re going to build: RequirementsThis tutorial builds on the concepts introduced in the previous Getting Started tutorials. Therefore, it’s highly recommended that you complete Getting Started tutorials 1-4 before beginning this one. Building for iPadFrom an application perspective, building for the iPad is nearly the same process as building for the iPhone. Everything that we’ve 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; it’s 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, let’s 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, let’s take a look at actually creating an iPad application. Creating our iPad ApplicationOpen up MonoDevelop (MD) and create a new solution. In the We’re going to make a very simple application, so choose The resulting project looks nearly identical to the Hello, iPhone application we created in an earlier Getting Started tutorial: Project OptionsIn fact, the only real difference is in our .plist file. If we right-click on the project, and choose By changing Devices setting to iPad, the dialogue also gives options specific to the device. Interface Builder and iPad ViewsEditing iPad .xib files in Interface Builder (IB), is exactly like editing iPhone .xib files, except the designer is much larger. Double-click on the Let’s add a label to the view, and save it: We don’t 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 AppNow let’s build and run our iPad app. If we look at the That’s it! We’ve built our first MonoTouch iPad application! iPad IconsiPad 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:
To add these icons, follow the same procedure we did for the Hello, iPhone application: right-click on the project and choose To configure these icons, either double-click on the iPad Default Loading ScreensSpecifying 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:
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 we’ve covered iPad applications, let’s take a look at how to build apps that target both the iPhone and iPad. Universal ApplicationsUniversal 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 Fortunately for us, MonoDevelop ships with a universal project template that contains the basic code to accomplish this. Let’s take a look at it. Universal Project TemplateLet’s create a new solution, this time we’ll choose Let’s name the project If you take a look at the project structure created from this template, you’ll notice something a little different. There is one view controller, but two associated .xib files:
Programmatic Device DetectionTo understand how this works, let’s take a look at the 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 Once we’ve 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, we’re passing either Creating the User InterfaceSo far, so good, but let’s actually put this in action. First, let’s open the We’re going to update the bottom label with some text when the button is clicked, so make sure it’s fairly wide, so that the text doesn’t get truncated. Next, we’ll do the same thing with the Again, be sure to make the bottom label fairly wide so the text doesn’t get truncated. Sharing Outlets and Actions Across Multiple ViewsSo 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. Let’s 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:
The Our .h file should have the following Outlet code: @property (nonatomic, retain) IBOutlet UIButton *btnClickMe; @property (nonatomic, retain) IBOutlet UILabel *lblOutput; Next, let’s open up the iPad view. This time, we’re 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. Let’s 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. Let’s modify our 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 Complex Universal ApplicationsThe approach we’ve 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, we’d 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 public partial class AppDelegate : UIApplicationDelegate
{
// class-level declarations
UIWindow window;
UIViewController homeScreen;
…
}
Then, in the 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. SummaryCongratulations, 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 you’ve been going through these tutorials from start to finish, you’re now well on your way to becoming a proficient MonoTouch iOS developer! |