tabBarController and navigationControllers in landscape mode, episode II
Asked Answered
R

7

6

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.

Rondeau answered 16/4, 2009 at 14:59 Comment(0)
P
4

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;
}
Prognathous answered 21/4, 2009 at 13:34 Comment(1)
Rich, thank you very much. The proposed solution works like a charm ;-) This problem was driving me crazy! I did not realize that the proper way to do this also requires checking simultaneously for the visibleViewController. Great answer!Rondeau
R
7

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
Runoff answered 31/7, 2009 at 10:43 Comment(3)
Actually this isn't even neccessary. UITabBarController seems to do something similar, but only agrees to orientations, every controller of each tab supports.Runoff
Andreas, that would be terrific news! But I'm not seeing that in my app. In my case, unless I move along the request to the view controller, the rotation request never comes through. As soon as I put it in, the Tab Bar controller is asked first, then I'm able to propagate to the VC. If there's something I'm missing, please advise! In fact, I'm still having trouble when the VC is within the "More" section of the Tab Bar. In that case, the Tab Bar controller never even gets called. :(Widget
I've posted my saga in a new thread. is.gd/2emkj (redirects back to stackoverflow.com)Widget
P
4

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;
}
Prognathous answered 21/4, 2009 at 13:34 Comment(1)
Rich, thank you very much. The proposed solution works like a charm ;-) This problem was driving me crazy! I did not realize that the proper way to do this also requires checking simultaneously for the visibleViewController. Great answer!Rondeau
P
3

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!

Pastelist answered 12/8, 2009 at 23:20 Comment(2)
Ah-ha! When I try to rotate the interface, and ONLY when I'm using a VC within the More View Controller, I see this in my console log: "Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations." Umm ... news flash, I'm NOT using two-stage animation! That is, I'm not responding to willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration: at all. Apparently the More view controller is, and thus I'm never getting the call to willAnimateRotationToInterfaceOrientation:duration: ... :(Widget
In fact, if I try to look out for the SecondHalf version ... I don't get that call either. Hmm ...Widget
T
2

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

Toname answered 9/1, 2010 at 20:11 Comment(1)
Thanks. I had to implement this because I was creating my tabbarcontroller programatically and it seems that it couldn't find the shouldAutorotateToInterfaceOrientation method, even if it defined on the same viewcontroller or appdelegate. I had to this to support orientation change on iOS5, not necessary on iOS6Diplegia
J
1

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];
}
Jareb answered 4/4, 2013 at 9:40 Comment(0)
B
0

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

Bertie answered 4/8, 2010 at 23:37 Comment(0)
O
0

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.

Oulu answered 18/2, 2011 at 7:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.