16

Ack! I had my tabbar rotation issues resolved finally in iOS 5, but iOS 6 and xcode seem to have broken things... here is what I have:

Target App Summary includes: Supported Interface Orientations - Portraint, Landscape Left, Landscape Right

Every Single View in the App has the following methods:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
    return ((interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown) &&
            (interfaceOrientation != UIInterfaceOrientationLandscapeLeft) &&
            (interfaceOrientation != UIInterfaceOrientationLandscapeRight));
} else {
    return YES;
}
}

- (BOOL)shouldAutorotate
{
NSLog(@"am I called1?");
return NO;
}

-(NSUInteger)supportedInterfaceOrientations{
   NSLog(@"am I called?");
   return UIInterfaceOrientationMaskPortrait;
}

In the views that are not part of the tab bar, rotation is blocked. In ALL the views of the tabbar (there are 5) the app never calls ShouldAutorotate and so rotates. It does seem supportedInterfaceOrientations gets called once when a view loads, but not when it appears if I switch between views, because I get the NSLog, but it seems to ignore the MaskPortrait setting.

I have to leave the landscape enabled in the target because I have a single video player view that needs to rotate (and it does so, fine)

Is this a tabbar bug in iOS 6? Do I need to disable the rotation of the views differently? The shouldautorotatetointerfaceorientation worked great in ios 5

I've been at it for a while

Thanks, Zack

Nat Ritmeyer
  • 5,634
  • 8
  • 45
  • 58
Zachary Fisher
  • 781
  • 1
  • 7
  • 18
  • So, out of frustration, I've created a barbones uitabbar app in xcode using JUST the tab bar application template. I added the (BOOL)shouldAutorotate { return NO; } and -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } to both windows of the default tab view. However, both windows still rotate. Is this a bug in iOS 6.0? Has anyone been able to prevent a tabbar from rotating windows without disabling ALL windows from rotating in the target -> summary? – Zachary Fisher Sep 21 '12 at 02:21

8 Answers8

36

Zack, I ran into this same issue. It's because you have your viewController embedded inside of a TabBar Controller or UINavigationController and the calls to these methods are happening inside those instead of your normal View (Changed in iOS6).

I ran into this issue because I was presenting a viewController embedded inside a UINavigationController on all my modal views that had Navigation to different views (Signup Process, Login, etc).

My simple fix was to create a CATEGORY for UINavigationController that includes these two methods. I have shouldAutorotate returning NO anyway because I don't want my modal views rotating. Your fix may be this simple, give it a try. Hope it helps.

I created a category and named it autoRotate and selected theUINavigationController option. The M+H file are below.

#import "UINavigationController+autoRotate.h"

@implementation UINavigationController (autoRotate)

-(BOOL)shouldAutorotate {
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

@end

... and the category .h:

#import <UIKit/UIKit.h>

@interface UINavigationController (autoRotate)

-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;

@end
Kunani
  • 476
  • 4
  • 3
  • goo solution and +1 for this. – Ilker Baltaci Sep 25 '12 at 12:29
  • 1
    Kunani, this was great. I actually made a category for UITabBarController+autoRotate and it worked perfectly! You are a life saver. – Zachary Fisher Sep 26 '12 at 01:16
  • hey Kunani...this is not working for me so it might be possible that i am doing something wrong in my code so can you please...give source code for this demo ? – Sarafaraz Babi Oct 02 '12 at 09:36
  • Great answer Kunani. I wonder what you would have done in my situation, please take a look at my question if you have some time over. Cheers http://stackoverflow.com/questions/13195230/uitabbarcontroller-uinavigationcontroller-rotation-issues – Jesper Martensson Nov 02 '12 at 12:28
  • Thanks this worked. Seems stupid that we would have to do this though :S – Luke Nov 24 '12 at 05:33
  • Keep in mind that overriding methods with a category is undefined behavior if the target class also implements it with a category (which is an internal implementation detail and can't be relied on). The runtime may call either implementation. This may work in the current implementation, but subclassing is safer. – Rob Napier Feb 22 '13 at 20:59
  • This is great. One additional tip: if you are using tab bar controllers and navigation controllers, some view controllers will look to the tab bar controller for rotation, others to the navigation controller. In particular, using presentViewController:animated:completion: uses the navigation controller, while its delegate might be using the tab bar controller. – Adrian Harris Crowne Sep 20 '13 at 17:15
11

If you have a tab bar like I did, the only thing you need to do is to add the following to your delegate .m file,

#import "AppDelegate.h"

//UITabBarController category to set the view rotations for ios 6
@implementation UITabBarController (Background)

-(BOOL)shouldAutorotate
{
    //I don't want to support auto rotate, but you can return any value you want here
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    //I want to only support portrait mode
    return UIInterfaceOrientationMaskPortrait;
}

@end


/////here starts the implementation of the app delegate which is gonna be whatever you currently have on your .m delegate

@implementation AppDelegate

// delegate methods and other stuff

@end
Mona
  • 5,939
  • 3
  • 28
  • 33
7

I also had the issue that I needed some views to rotate and others not with several Navigation Controllers. I did this by telling the NavigationController to look in the view controller. Here is what I did.

I create a UINavigationController class called RootNavigationController and designated that class as the Custom Class for the Navigation Controllers in storyboard. In the RootNavigationController.m I added the following methods;

- (BOOL)shouldAutorotate {

    return [self.visibleViewController shouldAutorotate];
}

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

In each view controller .m file I also added the following methods.

- (BOOL)shouldAutorotate {
    //return yes or no
}

- (NSUInteger)supportedInterfaceOrientations{
    //return supported orientation masks
}

Doing this allows me to set orientation for each view in its view controller.

Worked for me anyway…

Jeremy
  • 71
  • 2
  • smooth man. real smooth. I wonder why Apple decided to go this way? – pir800 Sep 28 '12 at 23:48
  • 5
    One problem I'm having with this code is popping a viewcontroller while in landscape to a viewcontroller that only supports portrait. I can't for the life of me figure out how to force it back to portrait before popping. I've tried changing the status bar orientation and doing the old trick of setting the orientation of the current device but neither have an effect (changing the current device is no longer allowed) – pir800 Sep 29 '12 at 18:57
  • I'm having the same problem. @pir800, did you have any luck fixing this? – kevboh Dec 12 '12 at 20:06
  • 2
    @pir800 , here's a solution to forcing correct orientation when popping/pushing : http://stackoverflow.com/a/14445888/338514 – Rafael Nobre Jan 23 '13 at 18:32
7

My situation is:

  • UITabBarController has 2 items: 2 Navigation controller
  • UINavigationController1 withRootView: ViewController1
  • UINavigationController2 withRootView: ViewController2.
  • Now i want ViewController1 set shouldAutorotate:NO/maskPortrait and ViewController2 set shouldAutorotate/MaskAll.

So my implement: Create UITabBarController category and UINavigationCntroller category like

UITabBarController+autoRotate.h

@interface UITabBarController (autoRotate)

-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;

@end

UITabBarController+autoRotate.m

#import "UITabBarController+autoRotate.h"

@implementation UITabBarController (autoRotate)

- (BOOL)shouldAutorotate {
    return [self.selectedViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
    return [self.selectedViewController supportedInterfaceOrientations];
}

@end

UINavigationController+autoRotate.h

@interface UINavigationController (autoRotate)

-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;

@end

UINavigationController+autoRotate.m

@implementation UINavigationController (autoRotate)

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

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

@end

UIViewController1.m

- (BOOL)shouldAutorotate {
    return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
   return UIInterfaceOrientationMaskPortrait;;
}

UIViewController2.m

- (BOOL)shouldAutorotate {
   return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
   return UIInterfaceOrientationMaskAll;
}

It worked like a charm!

Võ Huy Hưng
  • 93
  • 1
  • 4
  • This works fine except when VC2 pops out in landscape mode, VC1 does NOT rotate back to portrait - stays in Landscape mode. – DroidDev Dec 22 '21 at 04:07
0

In my case, I had a navigation controller embedded within a UITabBarController, and what worked was creating a category like Kunani defined, but extendind UITabBarController instead of UINavigationController. It worked like a charm :)

#import "UINavigationController+autoRotate.h"

@implementation UINavigationController (autoRotate)

-(BOOL)shouldAutorotate {
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

@end

And .h file:

#import <UIKit/UIKit.h>

@interface UINavigationController (autoRotate)

-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;

@end
dleal
  • 642
  • 6
  • 19
0

This will do it in Swift

extension UITabBarController {
    public override func shouldAutorotate() -> Bool {
        if let selected = self.selectedViewController {
            return selected.shouldAutorotate()
        } else {
            return false
        }
    }

    public override func supportedInterfaceOrientations() -> Int {
        if let selected = self.selectedViewController {
            return selected.supportedInterfaceOrientations()
        } else {
            return Int(UIInterfaceOrientationMask.Portrait.rawValue)
        }
    }
}

extension UINavigationController {
    public override func shouldAutorotate() -> Bool {
        return self.visibleViewController.shouldAutorotate()
    }

    public override func supportedInterfaceOrientations() -> Int {
        return self.visibleViewController.supportedInterfaceOrientations()
    }
}
MacTeo
  • 2,656
  • 1
  • 20
  • 23
0

https://stackoverflow.com/a/30632505/2298002

there are a lot of ambiguous or unforeseen results when handling this situation, especially when it comes to maintaining the orientation for only a specific view controller and not effecting the rest of the app. this algorithm seems to hand all for me

https://stackoverflow.com/a/30632505/2298002

Community
  • 1
  • 1
greenhouse
  • 1,231
  • 14
  • 19
-1

You should add this thing in the UIViewController1.m to make sure that the previous orientation status is reconstructed:

 (void)viewDidAppear:(BOOL)animated 
{

    [[UIDevice currentDevice] performSelector:NSSelectorFromString(@"setOrientation:") 
    withObject:(id)UIInterfaceOrientationPortrait];
}

Perfect!

Kristoffer Sall-Storgaard
  • 10,576
  • 5
  • 36
  • 46
  • setOrientation is a private method of UIDevice and you can get rejected for submitting such code – Will Jan 14 '14 at 02:29