SaltyNuts
SaltyNuts

Reputation: 5168

Disable Autorotation on iOS 7 for a single presented ViewController

I have a UIViewController, which is presented modally (full screen) and I would like to disable autorotation in that view. I do not want to restrict it to landscape or portrait, just would like it to stay in whatever orientation it was originally presented.

On iOS 6 it was sufficient to just override the method:

- (BOOL)shouldAutorotate {
    return NO;
}

And it did exactly what I wanted. On iOS 7 however, this seems to have no effect. The method does get called, but the return value seems to be ignored by the OS - it auto rotates no matter what.

The documentation does not mention any changes to this method. How can I achieve the desired effect on iOS 7?

Edit: the view controller is being presented (not pushed!) by a UINavigationViewController:

[self.navigationController presentViewController:vc animated:YES completion:nil];

Solution:

As odd as it may seem, but this solution was not published in the numerous existing questions on this topic. On iOS 7 it seems the answer the UINavigationController gives to shouldAutorotate is what the OS acts on. We need to subclass UINavigationController to modify its behaviour.

When dealing with a regular navigation stack it is indeed sufficient to just use [self.topViewController shouldAutorotate], but when there is modal view, it resides in self.presentedViewController, not self.topViewController. Thus the full solution looks like:

- (BOOL)shouldAutorotate {
    UIViewController *vc;
    if (self.presentedViewController) vc = self.presentedViewController;
    else vc = [self topViewController];
    return [vc shouldAutorotate];
}

Upvotes: 8

Views: 3858

Answers (2)

Craig Siemens
Craig Siemens

Reputation: 13266

So I just tried you code and it worked which leads me to believe that you are presenting your UIViewController in a UINavigationController. For whatever reason, iOS 7 changed how UINavigationController handle rotations.

The easiest solution is to create a subclass of UINavigationController that overrides the shouldAutorotate method and returns the value from the topViewController.

@interface CustomNavigationController : UINavigationController

@end

@implementation CustomNavigationController

- (BOOL)shouldAutorotate
{
    return [[self topViewController] shouldAutorotate];
}

@end

So instead of doing this, where viewController is your object that return NO for shouldAutorotate.

UINavigaitonController *navController = [UINavigationController alloc] initWithRootViewController:viewController];
[self presentViewController:navController animated:YES completion:nil];

You would use the CustomNavigationController instead

CustomNavigationController *customNavController = [CustomNavigationController alloc] initWithRootViewController:viewController];
[self presentViewController:customNavController animated:YES completion:nil];

Upvotes: 5

ares777
ares777

Reputation: 3628

#import <objc/message.h>

-(void)viewDidAppear:(BOOL)animated{             

    objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), UIInterfaceOrientationPortrait );

 }

see How do I programmatically set device orientation in iOS7?

But take the case you are using this method because it is a private API, and your app may be rejected by Apple. So, maybe is better to set orientation from Project details -> General -> Deployment Info tab, choose Landscape Left and Landscape Right choice only. This can be a better approach, if all your views need only one kind of orientation.

Upvotes: -1

Related Questions