multicolored blocks reading APP

Build an iPad Application Using MonoTouch, C#, and .NET

How to use Xamarin MonoTouch to build iPad-specific features into iOS applications

Since its release in March 2010, the iPad has taken the world by storm. For more information on mobile development, see "Mobile Development Options for .NET Developers" and "Better Mobile Website Development Using the jQuery Mobile Library." Each new iPad release has launched the device further and further into our lives. Here are some interesting facts that we have seen over the past few years along with some market share analysis:

  • The school that my teenagers attend here in Knoxville, Tennessee, was the first school in the United States to integrate the iPad into its teaching program and its curriculum. Many schools have since followed suit.
  • There are a healthy number of applications in a variety of market segments. In fact, there is a market for iPad point-of-sale systems.
  • The iPad is a popular device and growing more so each day. comScore states that one in four smartphone owners also owns a tablet. We also know that the iPad comprises 68 percent of the tablet market.
  • eMarketer recently issued a report stating that the number of iPad users is expected to grow by 90 percent in the US in 2012.

No matter how you slice the data, tablet usage is growing, and the iPad is currently leading the pack. The question for .NET developers is "How can I get me some of that?" Xamarin's MonoTouch offers help, by providing the means for .NET developers to leverage their C# and .NET coding skills to develop iPad applications. MonoTouch has supported the iPad since the initial release of the iOS 3.2 beta SDK all the way up to the most recent iOS SDK, which supports the iPad. In this article, we'll look at targeting the iPad and how we can take advantage of iPad-specific features in our iOS applications written with MonoTouch.

iPad Programming Support

Apple has done a good job of supporting iPad application developers -- for example, by carrying over familiar iPhone development concepts. At a basic level, programming the iPad is just like programming an iPhone, except that developers have more screen real estate. The concepts are the same: We have UILabels, UIButtons, UIPickers, and all the same controls that we're already used to. The only control that's new to the iPad is a UISplitViewcontroller, which we will discuss later.

What About MonoTouch?

MonoTouch allows developers to target the iPad in one of three ways, as shown in the MonoDevelop New Solution dialog in Figure 1:

  • iPhone applications running on the iPad. Thankfully, the iPad can run iPhone applications as is. This provides iPad users with a large group of applications to run. Given that many applications are written by individual developers with limited time and resources, this is a good option. However, users want applications that are designed for the platforms they use.
  • iPad applications that target only the iPad. In this option, you build an iPad application that will target the iPad and only the iPad. This option allows developers to build iPad applications for their iPads. We are developers who want to give our clients the applications they want. This means that we need to understand how to develop applications for the iPad. Fortunately, MonoTouch allows us to write applications that can natively target the iPad.
  • Universal applications that can target both iPhone and iPad. This is the best option of the three. In this scenario, a single application can be written that will run natively on either the iPhone or iPad.

Figure 1: Creating a new project for an iPad application in MonoDevelop
Figure 1: Creating a new project for an iPad application in MonoDevelop

iPad Development Support

Once you have created a new iPad project, one item to notice in MonoDevelop is in the project properties. Within the project properties, you can set the type of application (i.e., target), as shown in Figure 2.

Figure 2: Setting the iOS application target in MonoTouch
Figure 2: Setting the iOS application target in MonoTouch

After your application is compiled, the next step is to determine how to debug the application. For this article, I'm assuming that you're familiar with the debugging process in MonoDevelop. Have you noticed that you can select the type of device you will debug with? Figure 3 shows the type of display you will see if you are debugging a universal application. As you can see in Figure 3, you have the option of debugging with either the iPhone Simulator or iPad Simulator.

Figure 3: MonoDevelop debugger for a universal application
Figure 3: MonoDevelop debugger for a universal application

The next step in the process of looking at the tools is to investigate what the iOS Simulator provides. Most iPhone developers are familiar with the Simulator. In Figure 4, you can see two different features of the Simulator.

Figure 4: iOS Simulator
Figure 4: iOS Simulator

These Simulator features are:

  • The simulator does support the iPad, as Figure 4 shows.
  • Notice in the menu bar, that under Hardware, Device, there are two options for developing with the iPad: the iPad and new iPad (Retina) options. One suggestion here is to not use the iPad (Retina) display if your development device doesn't have enough screen real estate to display the screen properly. If you do attempt to use the iPad (Retina) and your development system doesn't have a large enough display, you will need to scroll right to left and up and down to see the entire device screen.

Supporting the iPad's Retina Display

On March 7, 2012, Apple announced the third-generation iPad, which is officially called "the new iPad." This version contains the same physical dimensions as previous versions of the device; however, inside the device are many new features. There is a new dual-core A5X CPU, quad-core graphics capability in the CPU, and a new Retina-level display with support for 2048 x 1536 pixels. This is four times the display resolution of the first- and second-generation iPads, which had 1024 x 768 pixels of resolution. As one can imagine, the update to the iPad has presented the user with amazing graphical capabilities.

MonoTouch and MonoDevelop support the various icon types used in the new iPad. Figure 5 shows how MonoDevelop supports the various built-in icons in iOS and the iPad Retina icons specifically.

Figure 5: MonoDevelop's support for built-in iOS icons, including iPad Retina icons
Figure 5: MonoDevelop's support for built-in iOS icons, including iPad Retina icons

What About Application Images?

This takes care of the built-in image in iOS for Retina displays. What about the images that are a part of your application? Fortunately, handling those images is easy and a built-in capability. For example, if you have an image named image.png, create a high-resolution named "[email protected]". Once you include the higher-resolution image in your project, go ahead and load the image.png file. On a device with a Retina display, the "[email protected]" file is chosen. On a non-Retina display, the device will load the image.png file as expected.

iPad Universal Applications

Now let's walk through the process of building a native iPad application in MonoTouch -- which is fairly similar to building an iPhone application. Let's start by building a universal application. To do so, in MonoDevelop, go to File, New, Solution. In the dialog, go to C#, MonoTouch, Universal, Single View Application. We'll use this project as a base example. The resulting project has an iPhone- and an iPad-specific .xib, as shown in Figure 6.

Figure 6: A new universal application project created in MonoDevelop
Figure 6: A new universal application project created in MonoDevelop

When you start to dig into the code, you will notice that AppDelegate.cs and Main.cs don't seem to have anything special in the way of code. When you open the UniversalSingleViewApplicationViewController.cs file, you will notice that the code has the following lines:

static bool UserInterfaceIdiomIsPhone {
	get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; }
}

public UniversalSingleViewApplicationViewController ()
	: base (UserInterfaceIdiomIsPhone ? "UniversalSingleViewApplicationViewController_iPhone" : "UniversalSingleViewApplicationViewController_iPad", null)
{
}

The 2 key items to notice in this code are:

  • The UserInterfaceIdiomIsPhone static read-only property will tell the application whether or not the device is an iPhone. If the device is an iPhone, a true is returned. If the device is an iPad, a false is returned because the device is not an iPhone. <
  • The initializer for the UniversalSingleViewApplicationViewController will determine whether the class is running on an iPhone or iPad. In this case, the string representing the device is determined and passed into the base UIViewController initializer that our control inherits from.

The next step is to design the .xib file that you are in. Just as with the iPhone, developers can open a .xib file that is designed for the iPad.

Along with the universal application in iOS, there is an associated Universal View Controller that can be used in your application. The Universal View Controller has the UserInterfaceIdiomIsPhone property that can be used in a .cs file to run code that is particular to an iPhone or iPad. In addition, the Universal View Controller also has a .xib file for the iPhone and iPad.

Note: Although it seems obvious that there would be a Universal View Controller, this is something I did not see for the longest time because I didn't see the vertical scrollbar on the right side of the screen when MonoTouch provided initial iPad support. I was programmatically creating user interfaces, which can be a little bit daunting when developers first take up a platform that is new to them. As a result, I like to mention the Universal View Controller and show it in the New File dialog box, as in Figure 7.

Figure 7: Creating an iOS Universal View Controller in MonoTouch
Figure 7: Creating an iOS Universal View Controller in MonoTouch

UISplitViewController

Now that you've seen the iPad and understand the basics of a universal application, let's dig into the iPad a little bit deeper. The first thing that we will see is the UISplitViewController class. This class is a container that allows a developer to manage two view controllers, which are displayed side by side. This class will be used to implement a master-detail interface. The left side of the display will be a list of items; the right side will present the detail information of the selected item from the left. The UISplitViewController is a control that's specific to the iPad. If a developer attempts to create a UISplitViewController on an iPhone or iPod Touch, an exception is generated.

The UISplitViewController has no user interface of its own. It is in charge of the presentation of two child view controllers, the master and detail controllers, and the transitions between the various orientations of the device. The UISplitViewController implements a delegate in the same way that the other objects in iOS implement delegates. The UISplitViewControllerDelegate allows the developer to manage the changes to the control.

Let's take a look at the code used with the controller. This code is within the AppDelegate.cs of an iPad project:

var controller = new RootViewController ();
var navigationController = new UINavigationController (controller);
var detailViewController = new DetailViewController ();
splitViewController = new UISplitViewController ();
splitViewController.WeakDelegate = detailViewController;
splitViewController.ViewControllers = new UIViewController[] {
	navigationController,
	detailViewController
};
window.RootViewController = splitViewController;

This code will set up the necessary controllers. Thankfully, the MonoTouch projects have this code already built for developers.

Now that we've seen the UISplitViewController at a high level, let's dig into using it in our universal application a little bit more.

Master Detail Example

One of the common scenarios for an iPad app is that of displaying the data in a master-detail display. Let's look at an example display that I created in the iPad, shown in Figure 8. I'll walk through the key parts of this code in the following sections.

Figure 8: Example master-detail display on an iPad
Figure 8: Example master-detail display on an iPad

Filling the Master

Filling the master controller of the app is actually a simple operation. In this example, there is just a static list of search terms. These search terms are stored in a .NET list of type string. When the application loads and the master controller is displayed, the loading occurs. This is done via the ViewDidLoad method of our master controller and is shown in the following single line of code as:

this.TableView.Source = new DataSource (this);

Now, I'm sure that you are wondering about the DataSource object. This is a single class that has been created and is an object that you create. Let's look at the code for this, shown in Listing 1.

class DataSource : UITableViewSource
{
RootViewController controller;

List masterItems;			
public DataSource (RootViewController controller)
{
	masterItems = new List();
	masterItems.Add(NSBundle.MainBundle.LocalizedString("MonoTouch", "MonoTouch"));
	masterItems.Add(NSBundle.MainBundle.LocalizedString("MonoDroid", "MonoDroid"));
	masterItems.Add(NSBundle.MainBundle.LocalizedString("iPhone", "iPhone"));
	masterItems.Add(NSBundle.MainBundle.LocalizedString("iPad", "iPad"));
	masterItems.Add("migueldeicaza");
	masterItems.Add("chrisntr");
	masterItems.Add("mikebluestein");
	masterItems.Add("wbm");
	masterItems.Sort();
	this.controller = controller;
}

// Customize the number of sections in the table view.
public override int NumberOfSections (UITableView tableView)
{
	return 1;
}

public override int RowsInSection (UITableView tableview, int section)
{
	return masterItems.Count;
}

// Customize the appearance of table view cells.
public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
	string cellIdentifier = "Cell";
	var cell = tableView.DequeueReusableCell (cellIdentifier);
	if (cell == null) {
		cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
		if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone) {
			cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
		}
	}
	
	// Configure the cell.
	//cell.TextLabel.Text = NSBundle.MainBundle.LocalizedString ("Detail", "Detail");
	cell.TextLabel.Text = masterItems[indexPath.Row];
	
	return cell;
}

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
	if (UserInterfaceIdiomIsPhone) {
		var DetailViewController = new DetailViewController ();
		// Pass the selected object to the new view controller.
		DetailViewController.SetDetailItem(masterItems[indexPath.Row]);
		controller.NavigationController.PushViewController (DetailViewController, true);
	}  else {
		var dvc = controller.SplitViewController.ViewControllers[1] as DetailViewController;
		dvc.SetDetailItem(masterItems[indexPath.Row]);
		// Navigation logic may go here -- for example, create and push another view controller.
	}
		
}

The main thing to notice in this code is that this is just a table data source – a topic that I covered in detail in my article on MonoTouch tables and data. The key part of the code to look at is the RowSelected method. In this method, the code will send the message to the SetDetailItem method that is exposed in the DetailViewController.

The SetDetailItem method is fairly simple in the DetailViewController. In this method, shown in the code example below, we will do two things:

  • Begin a Twitter search asynchronously. I covered this topic in the article on the UITableView and data ; see that article for more information.
  • If your iPad is in the Portrait orientation, the master list needs to be removed. The .Dismiss method will dissolve the pop-over display of content.
public void SetDetailItem (string newDetailItem)
{
	if ( ts == null )
	{
		ts = new TwitterSearch();	
	}
	ts.StartSearch(newDetailItem, new AsyncCallback(SearchCallback));
	
	if (this.popoverController != null)
		this.popoverController.Dismiss (true);
}

Buttons

There are valid needs to display a button in the navigation bar of an iPad application. Buttons are not particular to the iPad, but as a result of the increased screen space, it's likely that you'll need to add a button to an iPad app. Adding a button is a fairly simple operation in MonoTouch. The button is set up in code in our RootViewController.cs file, shown in Listing 2.

[Export("splitViewController:willHideViewController:withBarButtonItem:forPopoverController:")]
public void WillHideViewController (UISplitViewController svc, UIViewController vc,
	UIBarButtonItem barButtonItem, UIPopoverController pc)
{
	barButtonItem.Title = "Master";
	var items = new List ();
	items.Add (barButtonItem);
	items.AddRange (toolbar.Items);
	toolbar.SetItems (items.ToArray (), true);
	popoverController = pc;
}

[Export("splitViewController:willShowViewController:invalidatingBarButtonItem:")]
public void WillShowViewController (UISplitViewController svc, UIViewController vc,
	UIBarButtonItem button)
{
	// Called when the view is shown again in the split view, invalidating the button and popover controller.
	var items = new List (toolbar.Items);
	items.RemoveAt (0);
	toolbar.SetItems (items.ToArray (), true);
	popoverController = null;
}

Developers who would like to add a button in a slightly different way can do so using code that looks something like this:

uib = new UIBarButtonItem();
uib.Title = "Add Event";
uib.Clicked += HandleClicked;
this.NavigationItem.SetRightBarButtonItem(uib, true);

In this code, a UIBarButtonItem has been created, a title has been added to it, and a .Clicked event has been set up. The button has been added to the NavigationItem, and it is displayed on the right side.

Finally, here is the event handler that is set up in the preceding code:

void HandleClicked (object sender, EventArgs e)
{
// perform some operation such as opening a new screen.
}

Taking a Swipe?

When you work with the iPad, one of the first things you think about is the swipe action. With the swipe, we have an option to update the user interface based on a finger sliding left or right as well as up or down. When a user performs the swipe, the program needs to detect the swipe and then operate on it. The question then becomes: How does the program detect the swipe? In all honesty, performing a swipe is not specific to the iPad. However, given the iPad's increased display size, the swipe action is more commonly performed in the iPad. Let's look at the code necessary for the swipe operation.

The flow of the code that's shown in Listing 3 is as follows:

  1. We will use the iOS swipe gesture recognizer, so that we take advantage of features within the operating system. These recognizers will be set up at the class level.
  2. Each gesture recognizer will be set up. Setting up the recognizer involves object instantiation, assigning a target for the gesture recognition, assigning a direction to determine the swipe, assigning the delegate, and finally assigning the gesture recognizer to the view.
  3. Once the swipe occurs, the swipe must be decoded. This is handled within the HandleSwipe method that we created. Inside the passed-in recognizer, we can get information about the direction that is swiped, the number of touches that the user used in the swipe, and the location of the swipe.
public partial class UISwipesViewController : UIViewController
{
private UISwipeGestureRecognizer sgrLeft, sgrUp, sgrRight, sgrDown;
…
public override void ViewDidLoad ()
{
	base.ViewDidLoad ();
	
	// Perform any additional setup after loading the view, typically from a nib.
	// define the gesture recognizer 
	sgrLeft = new MonoTouch.UIKit.UISwipeGestureRecognizer();
	sgrDown = new MonoTouch.UIKit.UISwipeGestureRecognizer();
	sgrRight = new MonoTouch.UIKit.UISwipeGestureRecognizer();
	sgrUp = new MonoTouch.UIKit.UISwipeGestureRecognizer();
	
	// add the target to it, we put the instance itself of the controller 
	// and the class instance selector
	sgrLeft.AddTarget(this, MySelector);
	sgrRight.AddTarget(this, MySelector);
	sgrUp.AddTarget(this, MySelector);
	sgrDown.AddTarget(this, MySelector);
	
	// add the swipe direction, there are 4 of them (left, right, up, down). If other than one swipe is 
	// needed then more recognizers must be defined and added to the view - each for the direction
	sgrLeft.Direction = UISwipeGestureRecognizerDirection.Left; 
	sgrRight.Direction = UISwipeGestureRecognizerDirection.Right; 
	sgrUp.Direction = UISwipeGestureRecognizerDirection.Up; 
	sgrDown.Direction = UISwipeGestureRecognizerDirection.Down; 

	// also assign the delegate
	sgrLeft.Delegate = new SwipeRecognizerDelegate();
	sgrRight.Delegate = new SwipeRecognizerDelegate();
	sgrUp.Delegate = new SwipeRecognizerDelegate();
	sgrDown.Delegate = new SwipeRecognizerDelegate();
	 
	// and last, add the recognizer to this view to take actions
	this.View.AddGestureRecognizer(sgrLeft);
	this.View.AddGestureRecognizer(sgrUp);
	this.View.AddGestureRecognizer(sgrDown);
	this.View.AddGestureRecognizer(sgrRight);
}
[Export("HandleSwipe")]
public void HandleSwipe(UISwipeGestureRecognizer recognizer)
{
	// get the point of the swipe action
	PointF point = recognizer.LocationInView(this.View);
	int num = recognizer.NumberOfTouches;
	//recognizer.LocationOfTouch
	Console.WriteLine("Handle Swipe Called.");
	Console.WriteLine(String.Format ("{0} number of touches.", num));
	Console.WriteLine(String.Format ("Location: {0}, {1}", point.X, point.Y));
	// TODO: do something with the swipe
	StatusText.Text = "Handle Swipe called.";
	if ( recognizer.Direction == UISwipeGestureRecognizerDirection.Left ) {
		StatusText.Text = "Swipe Left";	
	}
	if ( recognizer.Direction == UISwipeGestureRecognizerDirection.Right ) {
		StatusText.Text = "Swipe Right";	
	}
	if ( recognizer.Direction == UISwipeGestureRecognizerDirection.Up ) {
		StatusText.Text = "Swipe Up";	
	}
	if ( recognizer.Direction == UISwipeGestureRecognizerDirection.Down ) {
		StatusText.Text = "Swipe Down";	
	}
}
	
public static Selector MySelector{
	get 
	{
		return new Selector("HandleSwipe");
	}
}

The next piece of code that will have to be created is the SwipeRecognizerDelegate. Here is the code for this:

using System;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
namespace UISwipes
{
	public class SwipeRecognizerDelegate : UIGestureRecognizerDelegate
	{
		public override bool ShouldReceiveTouch(UIGestureRecognizer recognizer, UITouch touch)
		{
			return true;
		}
		
	}
}

The result of this code is that when a user moves a finger across the screen, the swipe is processed, and the direction of the code swipe is presented to the user as text explaining the swipe detection.

Remember that UISwipeGestureRecognizer is not specific to the iPad. However, swipes are used by many applications that run on the iPad, so it is acceptable to mention them here. FYI, there are gesture recognizers in iOS, but the swipe gesture recognizer is the only one that we will work with when dealing with the iPad.

Step Up to iPad Development

As you've seen here, developing for the iPad is similar to developing for the iPhone. In addition to the items that I've discussed, there are other features that developers will encounter. Some of these features include the UIScrollView and the gratuitous page curl that makes for great demos.

MonoTouch provides the necessary APIs to target the iPad. Programming for the iPad is an easy step from programming for the iPhone. I hope that this article encourages you to take the opportunity to investigate the iPad as a platform for your .NET/C# skills.

Wallace B. "Wally" McClure is an ASPInsider, member of the national INETA Speakers Bureau, author of seven programming books including Professional iPhone Programming with MonoTouch and .NET/C# and Professional Android Programming with Mono for Android and .NET/C# , and a partner in Scalable Development.

More Dev Pro articles on iOS development:

References

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish