Orientation Changes for iPhone

There are two ways to change the orientation of controls when the device orientation changes. The simplest way is to use the controls found in the Size Inspector (shown here) to set behavior for individual controls.

If these settings do not allow the control that you need, the only other option is to change the view controller (and the view) when the orientation of the device changes. In this blog, we’ll show you how to do this. Let’s get started!

Start Xcode, select “Create a new Xcode project,” then choose the Empty Application template. Click Next, name the project “Orientation,” and choose options as shown:

Click Next, choose a location to save the project, and then click Create.

The first thing we will need to do is add a UIViewController (with a corresponding .xib). This will become the view controller for the Portrait orientation. We will then add another view controller for landscape orientation.

To add these view controllers, select File | New > File… from the menu, select the Objective – C class template, and make sure the “Subclass Of” box reads “UIViewController.” Name the first view controller “PortraitViewController” and the second “LandscapeViewController,” and for each, create a nib file for the user interface. Save each in the default location. When you are finished, the navigator should look like this:

Open PortraitViewController.xib and delete the view. Drag a new UIView object to the screen, open the Size Inspector panel and set the height of the view to 480 as shown:

(This is necessary because we cannot change the height of a template generated top level view.) Right – click the File’s Owner object, and drag from the circle to the right of the view object to the new View just created. Change the color of the view, and drag a label to the view, changing its text to “Portrait.”

In the LandscapeViewController.xib file, first delete the view as above, then drag a new UIView object to the screen. In the size inspector, change the width to 480 and the height to 320. Give this view a different background color than the portrait View, drag a label to the view, and change its text to “Landscape.” Remember to bind the new view to the view object in the File’s Owner as we did for the PortraitViewController. When finished, the two views should look like this:

Open LandscapeViewController.m and make this change to the shouldAutorotateToInterfaceOrientation: method:

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == (UIInterfaceOrientationLandscapeLeft |
            UIDeviceOrientationLandscapeRight));
}

This method must return YES for all supported orientations for the view controller. Here, we’re supporting both landscape orientations. Note the use of the bitwise OR operator ( | ) here.

Now open AppDelegate.h and make these changes:

#import <UIKit/UIKit.h>
#import "PortraitViewController.h"

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) PortraitViewController *rootVC;

@end

We’ve imported PortraitViewController.h and set up a property named rootVC. Make these changes in the applicationDidFinishLaunching: withOptions: method of AppDelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize rootVC = _rootVC;

(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.rootVC = [[PortraitViewController alloc] init];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window addSubview:self.rootVC.view];        
    [self.window makeKeyAndVisible];
    return YES;
}

After synthesizing the rootVC, we instantiate it using the init method, rather than initWithNibName: bundle:. PortraitViewController will call through to super’s initWithNibName: bundle: ; we’ll see that shortly.

Now open PortraitViewController.h and make these changes:

#import <UIKit/UIKit.h>
#import "LandscapeViewController.h"

@interface PortraitViewController : UIViewController

@property (nonatomic, assign) BOOL viewIsLandscape;
@property (nonatomic, strong) LandscapeViewController *landscapeVC;

@end

We’ve imported LandscapeViewController, and made a property of it (landscapeVC). Make these changes to PortraitViewController.m:

#import "PortraitViewController.h"

@interface PortraitViewController ()

@end

@implementation PortraitViewController

@synthesize viewIsLandscape;
@synthesize landscapeVC;

(id)init
{
    self = [super initWithNibName:@"PortraitViewController" bundle:nil];
    if (self) {
        self.viewIsLandscape = NO;
        self.landscapeVC = [[LandscapeViewController alloc] initWithNibName:@"LandscapeViewController"                                                           bundle:nil];
       
        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(orientationChanged:)
                                                     name:UIDeviceOrientationDidChangeNotification
                                                   object:nil];
    }
    return self;
}

(void)orientationChanged:(NSNotification *)notification
{
    UIDeviceOrientation devOrientation = [UIDevice currentDevice].orientation;
    if (UIDeviceOrientationIsLandscape(devOrientation) && !self.viewIsLandscape ) {
        [self presentModalViewController:self.landscapeVC animated:YES];
        self.viewIsLandscape = YES;
    } else if (UIDeviceOrientationIsPortrait(devOrientation) &&
               self.viewIsLandscape)
    {
        [self dismissModalViewControllerAnimated:YES];
        self.viewIsLandscape = NO;
    }
}
//…

(Leave the rest of the methods of the ViewController alone, just add these methods at the top, below the @implementation line). Here, we’ve overridden init to call super’s initWithNibName: bundle:, we’ve provided PortraitViewController.xib as the nib name. In the init method, we’ve also subscribed to the UIDeviceOrientationDidChangeNotification in the default notification center and provided the method “orientationChanged:” to be fired when this event occurs.

In orientationChanged, we detect the current device orientation, and either present the landscapeVC object as a modal view controller (if the device entered landscape orientation), or dismiss it (if the device entered portrait orientation). Note the use of the viewIsLandscape property to control the display of the proper view controller.

Now run the project. When the orientation changes, you should see the changes to the view take place:

Leave a Reply

Your email address will not be published. Required fields are marked *