问题
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.
回答1:
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;
}
回答2:
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
回答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!
回答4:
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
回答5:
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];
}
回答6:
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
回答7:
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.
来源:https://stackoverflow.com/questions/756536/tabbarcontroller-and-navigationcontrollers-in-landscape-mode-episode-ii