Question

I have a UITabBarController, and each tab handles a different UIViewController that pushes on the stack new controllers as needed. In two of these tabs I need, when a specific controller is reached, the ability to rotate the iPhone and visualize a view in landscape mode. After struggling a lot I have found that it is mandatory subclassing UITabBarController to override shouldAutorotateToInterfaceOrientation. However, if i simply return YES in the implementation, the following undesirable side effect arises:

every controller in every tab is automatically put in landscape mode when rotating the iPhone.

Even overriding shouldAutorotateToInterfaceOrientation in each controller to return NO does not work: when the iPhone is rotated, the controller is put in landscape mode.

I implemented shouldAutorotateToInterfaceOrientation as follows in the subclassed UITabBarController:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if([self selectedIndex] == 0 || [self selectedIndex] == 3)
        return YES;

    return NO;
}

So that only the two tabs I am interested in actually get support for landscape mode. Is there a way to support landscape mode for a specific controller on the stack of a particular tab?

I tried, without success, something like

(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

if([self selectedIndex] == 0 || [self selectedIndex] == 3)
{   
   if ([[self selectedViewController] isKindOfClass: [landscapeModeViewController class]])
           return YES;
    }

     return NO;

}

Also, I tried using the delegate method didSelectViewController, without success. Any help is greatly appreciated. Thank you.

Was it helpful?

Solution

This worked for me:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    if(self.selectedIndex == 0 && [[[self.viewControllers objectAtIndex:0] visibleViewController] isKindOfClass:[MyViewController class]])
        return YES;
    else
        return NO;
}

OTHER TIPS

Here's an extension to UITabBarController that delegates calls to shouldAutorotateToInterfaceOrientation to the currently selected child controller. Using this extension, you don't need to subclass UITabBarController anymore and you can use shouldAutorotateToInterfaceOrientation in your controllers like one would expect.

UITabBarController+Autorotate.h:

#import <UIKit/UIKit.h>

@interface UITabBarController (Autorotate)
@end

UITabBarController+Autorotate.m:

#import "UITabBarController+Autorotate.h"

@implementation UITabBarController (Autorotate)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    UIViewController *controller = self.selectedViewController;
    if ([controller isKindOfClass:[UINavigationController class]])
        controller = [(UINavigationController *)controller visibleViewController];
    return [controller shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

@end

I've been able to use this for a while now (from my app's tab bar controller) without problems:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
     return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

That way, in the appropriate VC, we get to do the real check, in this case for a photo gallery view (what else?):

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

My gallery view isn't even at the top-of-stack for a given Nav Controller. It still gets called.

Alas, I just discovered that this doesn't work so well when the VC is lurking within the MoreViewController (as opposed to the four main tabs). In that case, my gallery VC never gets called. I think it's because the VC I've been calling all along is really the nav controller from the selected tab, which then propagates things to the appropriate VC, in this case my photo gallery VC. But for the More VC, things don't work so nicely ... aaaand things go rotationally downhill from there. :\

I tried using the modifications by Andreas (see elsewhere in this thread), to no avail. Clues welcome!

I ran into the same issues as you did when working with the UITabBarController. I needed to control which UIViewControllers were allowed to rotate and which were not. My main problem was with the MORE tab. I did not want any of the UIViewControllers included in the MORE tab to rotate.

My solution was to create my own UITabBarController which I called MyTabBarController:

@interface MyTabBarController : UITabBarController <UITabBarDelegate> {

}

Then I implemented the shouldAutorotateToInterfaceOrientation method:

@implementation MyTabBarController

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
 UIViewController *controller = [self selectedViewController];

 if ((controller == [self moreNavigationController]) || ([self selectedIndex] == 4))
 {
  return interfaceOrientation == UIInterfaceOrientationPortrait;
 }

 return [controller shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

@end

I needed to discover if the MORE tab was selected. This is a two step process; when the MORE tab is selected initially the API returns a selectedIndex higher than 4 so I needed to compare the selected controller with the moreNavigationController.

If an UIViewController is selected from within the MORE tab then the selectedIndex is finally 4 but the selectedController is not the moreNavigationController anymore but the UIViewController selected.

The if ((controller == [self moreNavigationController]) || ([self selectedIndex] == 4)) takes care of this issue.

Now, when I run my application my UIViewControllers in the MORE tab are not rotated. I hope this will help other developers who are running into the same issues as I did.

Emilio

From what I have seen here and elsewhere I have stitched together a solution that uses the method shouldAutorotate since the old shouldAutorotateToInterfaceOrientation has been deprecated.

I have placed it inside a category to UITabBarController. I so hope this is admissible!

// call to method shouldAutorotate replaces call to method shouldAutorotateToInterfaceOrientation (deprecated)
-(BOOL)shouldAutorotate
{ // check whether selected view controller should autorotate    
  UIViewController *controller = self.selectedViewController;
  if ([controller isKindOfClass:[UINavigationController class]])
    { // in case it is a navigation controller: get visible view of that
      controller = [(UINavigationController *)controller visibleViewController];
    }
  return [controller shouldAutorotate];
}

Thank you, Thank you, Thank you. This has been 2 days in figuring out how to do this. Here is my take on all of your great help when you have a tabBarController with navigationControllers.

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

UIViewController *controller = self.selectedViewController;
if ([controller isKindOfClass:[UINavigationController class]])
    controller = [(UINavigationController *)controller visibleViewController];

if([controller isKindOfClass:[LOCviewcontroller class]])
    return YES;
else
    if([controller isKindOfClass:[personWebSiteView class]])
        return YES;
else return NO; 

}

Any critique of a neophite coder's code is always appreciated...jack

Is it really OK to subclass UITabBarController (as suggested in the accepted answer above)?

I've understood that Apples says something like "you should never ever subclass UITabBarController or UINavigationController" - or have I misunderstood?

Anyway; I found this tutorial where they subclasses a UIViewController in which they put a UITabBarController.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top