How to allow only single UIViewController to rotate in both Landscape and Portrait direction?

Solution 1:

Simple but it work very fine. IOS 7.1 and 8

AppDelegate.h

@property () BOOL restrictRotation;

AppDelegate.m

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if(self.restrictRotation)
    return UIInterfaceOrientationMaskPortrait;
else
    return UIInterfaceOrientationMaskAll;
}

ViewController

-(void) restrictRotation:(BOOL) restriction
{
    AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
    appDelegate.restrictRotation = restriction;
}

viewDidLoad

[self restrictRotation:YES]; or NO

Solution 2:

I think if you want to support just one viewcontroller rotation, it is not possible since application will follow orientations set by you in .plist file. An alternate you can follow is to support your app for both landscape and portrait, freeze all viewcontrollers rotation to portrait except for chat view.

EDIT

To subclass UINavigationController, create a new file with name e.g. CustomNavigationController and make it subclass of UINavigationController.

.h file

#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController

@end

.m file

#import "CustomNavigationController.h"

@interface CustomNavigationController ()

@end


@implementation CustomNavigationController

-(BOOL)shouldAutorotate
{
    return NO;
}

-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}


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

@end

Set the class of your UINavigationController in your main class xib as CustomNavigationController. Hope it helps ypu..

Solution 3:

Your view controller will never rotate to any position that is not supported by the app itself. You should enable all possible rotations and then in view controllers that are not supposed to rotate put the following lines

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

In ChatView, it should be:

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAll;
}

If you need to change your layout after a rotation you should implement the appropriate changes to your subviews in

- (void)viewWillLayoutSubviews

Use self.view.bounds to check the current size of the view, since self.view.frame doesn't change after rotations.

Solution 4:

for the specific viewcontroller.m you want to rotate

add this method:

- (BOOL)canAutoRotate
{
    return YES;
}

then inside your AppDelegate.m

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    UIViewController *currentViewController = [self topViewController];

    if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) {
        NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)];

        NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];

        [invocation setSelector:@selector(canAutoRotate)];
        [invocation setTarget:currentViewController];

        [invocation invoke];

        BOOL canAutorotate = NO;
        [invocation getReturnValue:&canAutorotate];

        if (canAutorotate) {
            return UIInterfaceOrientationMaskAll;
        }
    }

    return UIInterfaceOrientationMaskPortrait;
}

- (UIViewController *)topViewController
{
    return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}

- (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController
{
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}

Solution 5:

Ted's answer works well with the issue mentioned by Alexander of Norway. But I figured that issue is not happening the way Alexander explained,

When ViewController B which currently is in landscape (All orientations enabled) returns back to ViewController A. (Portrait only) after the user clicks on the back button, supportedInterfaceOrientationsForWindow doesn't get called and ViewController A ends up in landscape

Actually when ViewController B which currently is in landscape (All orientations enabled) returns back to ViewController A (Portrait only) after the user clicks on the back button, Appdelegate

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;

is getting called. But still root view controller is ViewController B (that rotation enabled view controller), ViewController A is not getting back to portrait orientation, since ViewController B is still returning

-(BOOL)shouldAutorotate{

    return YES;
}

So when you press back button return, "shouldAutorotate -> NO" in ViewController B. Then ViewController A will come to Portrait orientation. This is what I did

@property (nonatomic, assign) BOOL canAutoRotate;

#pragma mark - Public methods
- (BOOL)canAutoRotate
{
    return _canAutoRotate;
}

#pragma mark - Button actions
- (void)backButtonPressed:(UIButton *)sender {
    _canAutoRotate = NO;
   (...)
}

#pragma mark - Init
- (id)init{
    if(self=[super init]) {
        _canAutoRotate = YES;
    }
    return self;
}