Displaying different views when iPhone is rotated with MonoTouch

Posted by ESCOZ on Thursday, January 07, 2010

Here’s another control I developed while working on an iPhone application using MonoTouch.

Its very common for games to make use of the accelerometer inside the iPhone, but not so much for data-driven apps. One app that uses it very well is WeightBot, from TapBots, which display charts with different views of the data when you rotate the phone to the left or the right. I wanted to do the same for my application, and ended up writing another ViewController.

View controllers always need at least one UIView objects to display: the UIViewController has one, while the NavigationViewController has a list of many. In our case, the RotatingViewController will have three: one for portrait view, and two for landscape views:

 
[Register("RotatingViewController")]
public class RotatingViewController : UIViewController
{
    public RotatingViewController (IntPtr handle) : base(handle)  {}

    [Export("initWithCoder:")]
    public RotatingViewController (NSCoder coder) : base(coder) {}

    public RotatingViewController (string nibName, NSBundle bundle) 
         : base(nibName, bundle)    {}

    public RotatingViewController () {}

    public UIViewController LandscapeLeftViewController {get;set;}
    public UIViewController LandscapeRightViewController {get;set;}
    public UIViewController PortraitViewController {get;set;}
 }

I use here links to the UIViewController of the views, instead of directly to the view, because those views need to be set to allow rotation.

Now that we have the views, we need to register with the OS to receive notifications when the iPhone is rotated. For that, we will use NSNotificationCenter and the UIDevice.CurrentDevice object:

 
 public override void ViewDidLoad()
{
    notificationObserver  = NSNotificationCenter.DefaultCenter.AddObserver("UIDeviceOrientationDidChangeNotification", DeviceRotated );
}

 public override void ViewDidAppear (bool animated)
{
    UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications();
}

public override void ViewWillDisappear (bool animated)
{
    UIDevice.CurrentDevice.EndGeneratingDeviceOrientationNotifications();
}

private void DeviceRotated(NSNotification notification){
       // change the views on demand
}
 

We are registering the new observer “DeviceRotated” in the ViewDidLoad method because we want to make sure it is just created once, while we use the ViewDidAppear and ViewWillDisappear to only cause notifications when this view is visible. The deviceRotated method finally swaps the views accordingly to the mode of the view.

The entire source code can be found on GitHub. The class currently doesn’t handle special animations to transition between the views, which is something I’ll tackle later on. If your views are very complicated or use lots of memory, this can be a problem, as the views are not being created on demand.

Make sure you download the entire solution, which contains a sample application using the control.