29

I want to rotate ONLY one of my views within my app to either landscape left or landscape right. All my other views are in portrait mode and I have set my app to support only portrait mode. With orientation being changed in iOS 6, I am not sure how to do this. I have tried the following posted below. Can anyone tell me what I am doing wrong? Thanks!

-(BOOL)shouldAutorotate {
return YES;
}

-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{

return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;
} 

I have also tried:

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(didRotate:)
                                            name:UIDeviceOrientationDidChangeNotification
                                           object:nil];
return YES;//UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;
} 


 -(void)didRotate:(NSNotification *)notification {
 UIDeviceOrientation orientation = [[notification object] orientation];

if (orientation == UIDeviceOrientationLandscapeLeft) {
    [theImage setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)];
    [self.view setTransform:CGAffineTransformMakeRotation(M_PI / 2.0)];
} else if (orientation == UIDeviceOrientationLandscapeRight) {
    [theImage setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)];
    [self.view setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)];
} else if (orientation == UIDeviceOrientationPortraitUpsideDown) {
    [theImage setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)];
    [self.view setTransform:CGAffineTransformMakeRotation(M_PI / -2.0)];
} else if (orientation == UIDeviceOrientationPortrait) {
    [theImage setTransform:CGAffineTransformMakeRotation(M_PI / 2.0)];
    [self.view setTransform:CGAffineTransformMakeRotation(M_PI / 2.0)];
}
}
Alex G
  • 2,299
  • 5
  • 37
  • 54

7 Answers7

19

This worked for me How to force a UIViewController to Portrait orientation in iOS 6

Create a new category from UINavigationController overriding the rotating methods:

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

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

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [self.topViewController preferredInterfaceOrientationForPresentation];
}

@end 
ChavirA
  • 707
  • 8
  • 18
  • 1
    I've seen two solutions suggest using a category to override methods already — surely this is a really bad idea, because now all of the navigation controllers in your entire application will have those orientation methods set! – fatuhoku Jun 09 '15 at 21:12
6

There are changes in iOS 6 regarding handling view rotations. Only orientations defined in apps Info.plist are supported. Even if you are returning other ones.

Try to select all orientations as supported in your project.

Handling View Rotations

In iOS 6, your app supports the interface orientations defined in your app’s Info.plist file. A view controller can override the supportedInterfaceOrientations method to limit the list of supported orientations. Generally, the system calls this method only on the root view controller of the window or a view controller presented to fill the entire screen; child view controllers use the portion of the window provided for them by their parent view controller and no longer participate in directly in decisions about what rotations are supported. The intersection of the app’s orientation mask and the view controller’s orientation mask is used to determine which orientations a view controller can be rotated into.

You can override the preferredInterfaceOrientationForPresentation for a view controller that is intended to be presented full screen in a specific orientation.

In iOS 5 and earlier, the UIViewController class displays views in portrait mode only. To support additional orientations, you must override the shouldAutorotateToInterfaceOrientation: method and return YES for any orientations your subclass supports. If the autoresizing properties of your views are configured correctly, that may be all you have to do. However, the UIViewController class provides additional hooks for you to implement additional behaviors as needed. Generally, if your view controller is intended to be used as a child view controller, it should support all interface orientations.

When a rotation occurs for a visible view controller, the willRotateToInterfaceOrientation:duration:, willAnimateRotationToInterfaceOrientation:duration:, and didRotateFromInterfaceOrientation: methods are called during the rotation. The viewWillLayoutSubviews method is also called after the view is resized and positioned by its parent. If a view controller is not visible when an orientation change occurs, then the rotation methods are never called. However, the viewWillLayoutSubviews method is called when the view becomes visible. Your implementation of this method can call the statusBarOrientation method to determine the device orientation.

(C) Apple Docs: UIViewController

Community
  • 1
  • 1
Nekto
  • 17,837
  • 1
  • 55
  • 65
  • 1
    So after I set the plist to support all orientations, can you please explain what specific code is needed to support all my views that are portrait and then the only 1 view that requires landscape only? Thank so much. Will accept – Alex G Oct 07 '12 at 22:44
  • I tried - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return UIInterfaceOrientationMaskPortrait; } And it still rotated to landscape on views where I just wanted portrait. This is happening of course because I tried your suggestion of enabling all the orientations – Alex G Oct 08 '12 at 01:00
  • @AlexG why were you changing that property? It is said: `A view controller can override the supportedInterfaceOrientations method to limit the list of supported orientations.`? Override `supportedInterfaceOrientations` property and that's all. – Nekto Oct 08 '12 at 01:22
  • 1
    I tried that but the app crashes and says "Supported orientations has no common orientation". If I enable all of the possible orientations then it works but only if I rotate the phone to landscape, it won't automatically do it when the view loads and then also all my other views won't stop rotating to landscape, even if I return UIInterfaceOrientationMaskPortrait. Any other suggestions? Thanks so much I really appreciate it – Alex G Oct 08 '12 at 01:43
  • @AlexG Look here: http://stackoverflow.com/questions/12540597/supported-orientations-has-no-common-orientation-with-the-application-and-shoul – Nekto Oct 08 '12 at 02:01
  • @AlexG Did you get this working? If yes, could you please share the solution as I am also stuck up at same issue. – Parth Bhatt Oct 11 '12 at 04:40
  • @ParthBhatt No unfortunately after hours and hours of trying I have not managed too. If you figure it out, can you also please report back her? Thanks – Alex G Oct 13 '12 at 22:46
2

Follow the below steps

  • Create subclass of UINavigationController overriding the rotating methods.
  • In AppDelegate, create a BOOL islandscape property.
  • When a view is pushed/poped/present/dismiss, adjust this BOOL value.

Sample Project

I created a sample project for this which is working perfectly. Download and integrate in your project: https://www.dropbox.com/s/nl1wicbx52veq41/RotationDmeo.zip?dl=0

pkc456
  • 8,350
  • 38
  • 53
  • 109
0

I have a:

TabbarController -> NavigationController -> ViewController -> ViewController

I Subclassed UITabBarController and add....

-(NSUInteger)supportedInterfaceOrientations{
    if (self.selectedIndex >= 0 && self.selectedIndex < 100) {
        for (id vC in [[self.viewControllers objectAtIndex:(unsigned long)self.selectedIndex] viewControllers]) {
            if ([vC isKindOfClass:[CLASS_WHICH_SHOULD_ALLOW class]]) {
                return UIInterfaceOrientationMaskPortrait + UIInterfaceOrientationMaskLandscape;
            }
        }
    }
    
    return UIInterfaceOrientationMaskPortrait;
}
Alex Cio
  • 6,014
  • 5
  • 44
  • 74
Kurt57
  • 17
  • 1
  • 5
0

I have been searching for the solution for hours!

So after implementing the needed methods everywhere. shouldAutorotate doesn't need to be set to YES because it is already set as default:

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
     return UIInterfaceOrientationPortrait;
}

When it is time to show the UIViewController which needs the orientation different than the other views, I created a UIStoryboardSegue with this implementation inside:

#import "Showing.h"

@implementation Showing

- (void)perform{
    NSLog(@"Showing");
    UIViewController *sourceVC = self.sourceViewController;
    UIViewController *presentingVC = self.destinationViewController;

    [sourceVC.navigationController presentViewController:presentingVC 
                                                animated:YES 
                                              completion:nil];
}

@end

Inside the UIStoryboard I connected the views with this segue (showing):

enter image description here

It is just important, you are using

presentViewController:animated:completion:

AND NOT

pushViewController:animated:

otherwise the orientation won't be determined again.


I had been trying things like
[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];

OR this one inside the UIViewController where the orientation should change, and I also tryied to call it inside my custom UIStoryboardSegues before presentingViewController and dismissViewController:

[UIViewController attemptRotationToDeviceOrientation];

OR

NSNumber *numPortrait = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:numPortrait forKey:@"orientation"];

But no one of them worked. Of course the last example shouldn't be an option, because if apple will change anything of their api this could cause problems inside your app.

I also tried to use the AppDelegate method and always determine the orientation inside this method after looking for the correct UIInterfaceOrientation of the actual visibleViewController but then it sometimes happened to crash when switching from one to another orientation. So I'm still wondering why its made so complicated and there seems also not to be any documentation where it is explained correctly. Even following this part didn't help me.

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
0

UIViewController+OrientationPermissions.h

@interface UIViewController (OrientationPermissions)
   + (void)setSupportedOrientations:(UIInterfaceOrientationMask)supportedOrientations;
   + (UIInterfaceOrientationMask)supportedOrientations;
@end

UIViewController+OrientationPermissions.m

@implementation UIViewController (OrientationPermissions)
static UIInterfaceOrientationMask _supportedOrientations;

+ (void)setSupportedOrientations:    (UIInterfaceOrientationMask)supportedOrientations {
    _supportedOrientations = supportedOrientations;
}

+ (UIInterfaceOrientationMask)supportedOrientations {
    return _supportedOrientations;
}

@end

In your UIApplication delegate

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return [UIViewController supportedOrientations];
}

Then on a desired view controller do something like

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [UIViewController setSupportedOrientations:UIInterfaceOrientationMaskAll];
}

Don't forget to reset mask before leaving this view controller

Note, if you are using UINavigationController or UITabBarController, see https://stackoverflow.com/a/28220616/821994 how to bypass that

Community
  • 1
  • 1
-2

Defiantly work Please try. I solve after 2 days

//AppDelegate.m - this method is not available pre-iOS6 unfortunately

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

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

return orientations;
}

//MyViewController.m - return whatever orientations you want to support for each UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}
Ketan Ubhada
  • 275
  • 3
  • 14