Setting screen orientations in iOS

by


Recently I started a project which required an iOS app to be locked in landscape orientation. The method mentioned below was always the standard for locking/setting the orientation, but iOS 6 deprecated this method. This post will show and explain some other options that I came across when investigating alternative options for locking the screen.

 
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];

I found 3 different ways to lock the orientation for an iOS app.
1: Creating a category for the UINavigationController class.
2: Subclassing the UINavigationController class.
3: Define the orientation on a screen by screen basis

1: Creating category for UINavigationController

 
@implementation UINavigationController (Rotation_IOS6)

-(BOOL)shouldAutorotate{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
@end

Creating a category like this makes all of your navigation controllers respect the top level. This solution is not stable and it is highly recommended to not override these methods. The reason being is that at runtime it is undefined which implementation will be used, this one or the default Apple methods.

2: Subclassing UINavigationController

 
//LandscapeNavigationController.h
@interface LandscapeNavigationController : UINavigationController

//LandscapeNavigationController.m
@implementation LandscapeNavigationController
- (BOOL)shouldAutorotate {
    return NO;
}

-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return UIInterfaceOrientationLandscapeRight;
}

Subclassing the UINavigationController is a better way to set the orientation rather than create a category. This is because you still have the ability to call any of the super class methods.

 
LSViewController *landscape = [[LSViewController alloc]init];
LandscapeNavigationController *landscapeNav = [[LandscapeNavigationController alloc]initWithRootViewController:landscape];
[self presentViewController:landscapeNav animated:YES completion:NULL];

Then it is just as simple as instantiating an instance of your subclassed UINavigationController and setting a ViewController as the root. This also means that you have to define the screen orientations that you support in your subclassed UINavigationController.

3: Screen by screen

 
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
	NSUInteger orientations = UIInterfaceOrientationMaskAll;

	if(self.window.rootViewController){
    	UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
    	orientations = [presentedViewController supportedInterfaceOrientations];
	}

	return orientations;
}

This was the method that I chose to use as it was most flexible. This piece of code is placed inside the App Delegate .m file. It constantly checks the orientation of the last view controller on the stack.

 
- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscape;
} 

Then we simply add this to each view controller, so we can set different screen orientations for individual screens.

All credit goes to mister Ray Wenderlich for this final implementation.

Leave a Reply

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