Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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];
}
like image 330
SaltyNuts Avatar asked Mar 28 '14 14:03

SaltyNuts


1 Answers

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];
like image 106
Craig Siemens Avatar answered Sep 19 '22 09:09

Craig Siemens