19

I have a project using UINavigationController and segues working properly good, all of them rotate correctly, the thing is... I just want to disable autorotation on a specific UIViewController. I tried this:

- (BOOL)shouldAutorotateToInterfaceOrientation:
                               (UIInterfaceOrientation)interfaceOrientation {    
    return NO;
}

// New Autorotation support for iOS 6.
- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0){
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

but it's not working, my UIViewController keeps rotating automatically, any help will be welcome :)

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
Jesús Ayala
  • 2,743
  • 3
  • 32
  • 48
  • Autorotation commands only get sent to one view controller at any given time. the way I have dealt with this is by making all of my viewcontrollers that I can ever have on the screen into iVars in my appdelegate. Then depending on which viewcontroller is currently present I define what orientations are valid for the currently shown view. This doesn't work if you want multiple on screen at once though, sorry. – Putz1103 Jun 28 '13 at 18:10

5 Answers5

35

Per the View Controller Programing Guide

If you want to temporarily disable automatic rotation, avoid manipulating the orientation masks to do this. Instead, override the shouldAutorotate method on the initial view controller. This method is called before performing any autorotation. If it returns NO, then the rotation is suppressed.

So you need to subclass 'UINavigationController', implement shouldAutorotate and use your navigation controller class in your storyboard.

- (BOOL)shouldAutorotate
{
    id currentViewController = self.topViewController;

    if ([currentViewController isKindOfClass:[DetailViewController class]])
        return NO;

    return YES;
}
GayleDDS
  • 4,443
  • 22
  • 23
  • 4
    This might be obvious to some, but this solution does not work if you aren't employing a UINavigationController to control the navigation hierarchy of your app. – AWrightIV Jan 03 '15 at 01:28
14

Gonna complete GayleDDS's answer for the newbies just added a subclass of UINavigationController as he suggested like this:

#import "UINavigationController.h"
#import "MonthCalendarVC.h"

@implementation UINavigationController (overrides)
- (BOOL)shouldAutorotate
{
    id currentViewController = self.topViewController;

    if ([currentViewController isKindOfClass:[MonthCalendarVC class]])
        return NO;

    return YES;
}
@end

MonthCalendarVC is the viewController I want to be just in portrait mode (fixed), then just added the import to my appdelegate.m

#import "UINavigationController.h"

and that's it

Jesús Ayala
  • 2,743
  • 3
  • 32
  • 48
  • You seem to be subclassing UINavigationController and using the same name. Please can you explain a bit more and are we to use this new class as the main navigation controller? – elliotrock Feb 11 '14 at 12:19
  • As I understood navigation controller is active almost on my entire app because it shows my view controllers, so it asks if my current view controller is a MonthCalendar for allowing rotation or not, that's why I subclassed my UINavigationController adding that extra functionality – Jesús Ayala May 28 '14 at 00:05
  • That's not a subclass, that's a category on `UINavigationController`. The behaviour that's causing this to work is not guaranteed (overriding a method from a category). – Tony Arnold Nov 03 '14 at 02:08
5

Take a look at this other approach :

http://www.sebastianborggrewe.de/only-make-one-single-view-controller-rotate/

You just have to implement canRotate in a ViewController to allow rotation.

Works fine on iOS 7.

2015-01-30 Because sebastian's site seems to not work (404 error), this is my interpretation of its solution :

Unlike sebastian, I prefer using a protocol (like interface in C#) to avoid to create a method "-(void)canrotate:" in each of my view controller.

IRotationCapabilities.h
-----------------------

#ifndef NICE_APPS_IRotationCapabilities_h
#define NICE_APPS_IRotationCapabilities_h

@protocol IRotationCapabilities < NSObject >

// Empty protocol

@end

#endif


FirstViewController.h
---------------------

- ( void )viewWillAppear:( BOOL )animated
{
    [ super viewWillAppear:animated ];

    // Forces the portrait orientation, if needed
    if( ![ self conformsToProtocol:@protocol( IRotationCapabilities ) ] )
    {
        if( self.navigationController.interfaceOrientation != UIInterfaceOrientationPortrait )
        {
            [ [ UIDevice currentDevice ] setValue:@( 1 ) forKey:@"orientation" ];
        }
    }
}

SecondViewController.h
-----------------------

#import "IRotationCapabilities.h"

@interface SecondViewController : UIViewController < IRotationCapabilities >


AppDelegate.m
-------------

#pragma mark - Orientation management

- ( NSUInteger )application:( UIApplication * )application supportedInterfaceOrientationsForWindow:( UIWindow * )window
{

    if( __iPhone )
    {
        // Gets topmost/visible view controller
        UIViewController * currentViewController = [ self topViewController ];

        // Checks whether it implements rotation
        if( [ currentViewController conformsToProtocol:@protocol( IRotationCapabilities ) ] )
        {
            // Unlock landscape view orientations for this view controller
            return ( UIInterfaceOrientationMaskAllButUpsideDown );
        }

        // Allows only portrait orientation (standard behavior)
        return ( UIInterfaceOrientationMaskPortrait );
    }
    else
    {
        // Unlock landscape view orientations for iPad
        return ( UIInterfaceOrientationMaskAll );
    }
}
Chrstpsln
  • 765
  • 16
  • 31
4

Try to implement that in your UIViewController:

// implements the interface orientation (iOS 6.x)
@interface UINavigationController (RotationNone)
-(NSUInteger)supportedInterfaceOrientations;
@end

@implementation UINavigationController (RotationNone)
-(NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
@end
zero3nna
  • 2,770
  • 30
  • 28
  • hello!!! when I implemented that this rule, it applied for all my UIViewControllers, from the initial one to the last of them, I thought that it worked the first time :p – Jesús Ayala Jul 01 '13 at 14:53
0

I see someone asked about this in Swift. It's not immediately obvious, since the Objective-C methods are not methods at all in Swift, but rather computed vars:

override var shouldAutorotate: Bool { return false }
override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait }
Grimxn
  • 22,115
  • 10
  • 72
  • 85