I have a scenario where I'm creating the UIViewcontrollers dynamically and adding a UIView on top of it and pushing it to the navigation stack. This is how I have created my view Controller
UIViewController *vc = [UIViewController new];
[vc.view addSubView:customView];
[self.navigationController pushViewController vc];
When running my App on the device, my view doesn't autorotate. (If the VC had a implementation file, I would have returned YES in shouldAutorotate to make it work.)
Any pointers/help is appreciated.
EdITed based on George's Reply:
George's code works perfectly for ios6 and above. supportedInterfaceOrientations API has been made available for ios6.0+, Looking for a general fix for ios4.3+
Thanks..
If your navigation controller is a rootviewcontroller than add this category to the place you created it, if it doesn't help that add to the viewcontroller which must rotate
#implementation UINavigationController(Rotate)
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
#end
also may be your forgot to add in your app delegate
- (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskAll;
}
Edit:
For iOS 5 you need only to add this method to needed viewcontroller.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
Try this delegate in your viewcontroller
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return YES;
}
Related
I have iPAD app which has UIViewController A as root view Controller of Navigation Controller.
Now i have 3 more View Controllers B,C, D as subview of ViewController A.
I want B not to respond orientation while C and D should respond to it.
Currently with code all of them respond to orientation change.
There was another answer which says make two separate root ViewControllers and add them into windows View. One of them non rotating and other rotating. I cant do that because i have header in ViewController A which switches B,C,D to make them front viewController.
Anyway please suggest.
Thanks
You need to subclass the UINavigationController like this.
.H
#import <UIKit/UIKit.h>
#interface UINavigationController (Rotation)
- (BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
.M
#import "UINavigationController+Rotation.h"
#implementation UINavigationController (Rotation)
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([self visibleViewController] && [[self visibleViewController] isKindOfClass:[B class]]) {
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
#end
You can create subclass from UINavigationController or make category for it. And implement this methods:
-(BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
And then, in your controllers you should implement this methods with orientations which you want.
So I have the following hierarchy:
UINavigationController --> RootViewController (UIViewController) --> UITableViewController --> DetailViewController (UIViewController)
I want to lock the orientation on RootViewController to Portrait only, but leave all orientations for the rest view controllers.
If I put this to subclassed UINavigationController:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
All view controllers are then locked to portrait.
My question is, is there a way to lock only RootViewController to Portrait, but leave all options for other view controllers?
check the link here for fixing autorotation in iOS 6 and set orientation support per view basis: http://www.disalvotech.com/blog/app-development/iphone/ios-6-rotation-solution/
Here is what you could do:
Create a custom navigation controller that is a subclass of UINavigationController, in your .m file:
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
- (NSUInteger)supportedInterfaceOrientations
{
return self.topViewController.supportedInterfaceOrientations;
}
In your AppDelegate.h,
#interface AppDelegate : UIResponder <UIApplicationDelegate> {
UINavigationController *navigationController;
ViewController *viewController;
}
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController *viewController;
and in AppDelegate.m,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// set initial view
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
viewController = [[ViewController alloc] initWithNibName:#"RootViewController" bundle:nil];
navigationController = [[CustomNavigationController alloc]
initWithRootViewController:viewController]; // iOS 6 autorotation fix
[navigationController setNavigationBarHidden:YES animated:NO];
self.window = [[UIWindow alloc]
initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:navigationController]; // iOS 6 autorotation fix
//[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window // iOS 6 autorotation fix
{
return UIInterfaceOrientationMaskAll;
}
in your rootViewController, for whatever the event push the second view controller, do this:
- (IBAction)pushSecondViewController:(id)sender {
// push second view controller
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
}
in your each view controller, add
- (BOOL)shouldAutorotate{}
- (NSUInteger)supportedInterfaceOrientations{}
for iOS 6, you can set each view controller whatever the orientation support you want individually.
for iOS 5 and below, you can set
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{}
All the credits goes to John DiSalvo who wrote the sample app in the link.
Hope this helps.
in singleton
-(void)setOrientationSupport:(BOOL)flag{
flag_orientationSupport_ = flag;
}
-(BOOL)getOrientationSupport{
return flag_orientationSupport_;
}
in appdelegate
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([singleton getOrientationSupport])
return UIInterfaceOrientationMaskAll;
else
return UIInterfaceOrientationMaskPortrait;
}
add the following code in viewwillappear
for the viewcontroller you want support orientation
[singleton setOrientationSupport:YES];
to those controller you want disable orientation
[singleton setOrientationSupport:NO];
Put this in your Nav controller:
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
Now, add this to your root view controller:
- (BOOL)shouldAutorotate
{
return NO;
}
That should do it!
To delegate the responsibility of defining allowed orientations to subviews of a UINavigationController, one can use the visibleViewController property of the nav controller to make the navigation controller "ask" it's child views for their supported orientations. The following code should work (Swift) :
Sub-classed navigation controller:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if let visibleView = self.visibleViewController {
return visibleView.supportedInterfaceOrientations()
} else {
return UIInterfaceOrientationMask.All
}
}
Sub-view (root view) of nav controller:
// Restrict to portrait
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.Portrait
}
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):
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.
What I'm trying to do is the simplest concept. But, I'm just not getting any desired results.
My app is a standard Tab Bar app, all of the view controllers in each of the tabs support Portrait orientation only, which is exactly what I want.
However, in one section of the app, I display a modal view controller, which obviously covers the tab bar controller. It is a text input screen, and I would very much like this view to be able to support Landscape orientation as well as portrait. Then, once the user cancels out of that modal view controller, the tab bar controller would be displayed again, everything in portrait.
I have tried so many things, and nothing works. If I tell the app to support both orientations, then the rotations occur correctly on the modal, but also on the rest of the app, which I do not want.
I have tried implementing all the new shouldAutorotate and supportInterfaceOrientations methods, and nothing ever seems to work.
The closest attempt I had to almost working, was I created a UITabBarController category in my app delegate, to fowarded the shouldAutorotate and supportedInterfaceOrientations. This seemed to work initially, but for some reason, whenever cancelling out of my modal vc, my tab bar portion of the app was always shifted up by 20 pixels up behind the status bar?? I have no idea what that's all about.
I created a test app, in which there is no UITabBarController, and I was able to code my desired behavior with no problem, and it works perfectly. So, clearly something with regard to Tab Bar Controller is making this a difficult issue.
Please let me know what the trick is in solving this simple concept.
Thanks!
I was able to solve this by creating a couple of categories for UITabBarController and UINavigationController. Here is the code I used:
#implementation UITabBarController (rotations)
- (BOOL)shouldAutorotate
{
return [self.selectedViewController shouldAutorotate];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.selectedViewController supportedInterfaceOrientations];
}
#end
#implementation UINavigationController (navrotations)
- (BOOL)shouldAutorotate {
return [self.topViewController shouldAutorotate];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return [self.topViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
#end
Then, of course each view controller I display would simple need to respond to the shouldAutorotate and supportedInterfaceOrientations methods.
Apparently in ios6 and above, the way rotation works is different. So what you have to do is the following
In your .plist support all 4 orientations.
Subclass the UITabBarController (for e.g: CustomTabBarController)
In the CustomTabBarController put the following lines of code
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
In your app delegate or where ever you are initializing UITabBarController, replace those instances with CustomTabBarController instances.
In your modal controller put the lines
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
-(BOOL)shouldAutorotate{
return NO;
}
And it should all work.
Apparently the trick, I found is that, UITabBarController will not listen to your instructions. It will support all the orientations you mention in the .plist.
There fore you have to subclass it.
I tried doing all of the above and it works fine. Do let me know and I can send you the code if you want.
In my app I have multiple views, some views need to support both portrait and landscape, while other views need to support portrait only. Thus, in the project summary, I have all selected all orientations.
The below code worked to disable landscape mode on a given view controller prior to iOS 6:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Since shouldAutorotateToInterfaceOrientation was deprecated in iOS6 I've replaced the above with:
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMask.Portrait;
}
This method is correctly called when the view appears (I can set a breakpoint to ensure this), but the interface still rotates to landscape mode regardless of the fact that I'm returning the mask for portrait modes only. What am I doing wrong?
It seems that it's currently impossible to build an app that has different orientation requirements per view. It seems to only adhere to the orientations specified in the project summary.
If your are using a UINavigationController as the root window controller, it will be its shouldAutorotate & supportedInterfaceOrientations which would be called.
Idem if you are using a UITabBarController, and so on.
So the thing to do is to subclass your navigation/tabbar controller and override its shouldAutorotate & supportedInterfaceOrientations methods.
try change this code in AppDelegate.m
// self.window.rootViewController = self.navigationController;
[window setRootViewController:navigationController];
this is the complete answer
shouldAutorotateToInterfaceOrientation not being called in iOS 6
XD
In my case I have UINavigationController and my view controller inside. I had to subclass UINavigationController and, in order to support only Portrait, add this method:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
So in the UINavigationController subclass I need to check which orientation is supported by the current topViewController.
- (NSUInteger)supportedInterfaceOrientations
{
return [[self topViewController] supportedInterfaceOrientations];
}
One thing I've found is if you have an old application that is still doing
[window addSubView:viewcontroller.view]; //This is bad in so may ways but I see it all the time...
You will need to update that to:
[window setRootViewController:viewcontroller]; //since iOS 4
Once you do this the orientation should begin to work again.
The best way for iOS6 specifically is noted in "iOS6 By Tutorials" by the Ray Wenderlich team - http://www.raywenderlich.com/ and is better than subclassing UINavigationController for most cases.
I'm using iOS6 with a storyboard that includes a UINavigationController set as the initial view controller.
//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;
}
As stated by others if you're using a UINavigationController and you want to customize various views you'll want to subclass the UINavigationController and make sure you have these two components:
#implementation CustomNavigationController
// -------------------------------------------------------------------------------
// supportedInterfaceOrientations:
// Overridden to return the supportedInterfaceOrientations of the view controller
// at the top of the navigation stack.
// By default, UIViewController (and thus, UINavigationController) always returns
// UIInterfaceOrientationMaskAllButUpsideDown when the app is run on an iPhone.
// -------------------------------------------------------------------------------
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
// -------------------------------------------------------------------------------
// shouldAutorotate
// Overridden to return the shouldAutorotate value of the view controller
// at the top of the navigation stack.
// By default, UIViewController (and thus, UINavigationController) always returns
// YES when the app is run on an iPhone.
// -------------------------------------------------------------------------------
- (BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
Then in any view that is a portrait only you would include:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
And in any view that is everything but upside down:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
Basically as someone stated above, but in more detail:
Create a new file that is a subclass of UINavigationController
Go to your storyboard and then click on the Navigation Controller, set its class to the one that you just created
In this class(.m file) add the following code so it will remain in portrait mode:
(BOOL)shouldAutorotate
{
return NO;
}
(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
This worked for me
This code worked for me:
-(BOOL)shouldAutorotate {
return YES;
}
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
iPhone/iPad App Orientation check out my own answer
The best way I think is to do a Category rather than subclassing UINavigationController or UITabbarController
your UINavigationController+Rotation.h
#import <UIKit/UIKit.h>
#interface UINavigationController (Rotation)
#end
your UINavigationController+Rotation.m
#import "UINavigationController+Rotation.h"
#implementation UINavigationController (Rotation)
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
#end
Try to make all your controller import this category and this work like a charm.
You can even make a controller not rotating and pushing another controller that will rotate.
Try add shouldAutorotate method
Firstly in order to make your app work in only mode you should be returning UIInterfaceOrientationMaskLandscape. In case you want to keep only portrait mode, you are doing things correctly.
Just add the UISupportedInterfaceOrientations key in the Info.plist and assign the interface orientation values your app intends to keep.
Also, you should be returning false from shouldAutoRotate in case you want to avoid auto rotation totally. But I would suggest you to return true from here and specify the correct orientations in supportedInterfaceOrientations method.
I have the same situation as you. I know you already accepted an answer, but I thought I'd add another one anyway. This is the way I understand the new version of the rotation system to work. The root view controller is the only view controller to ever be called. The reasoning, I believe, is that with child view controllers it doesn't make sense often to rotate their views since they will just stay within the frame of the root view controller anyway.
So, what happens. First shouldAutorotate is called on the root view controller. If NO is returned then everything stops. If YES is returned then the supportedInterfaceOrientations method is invoked. If the interface orientation is confirmed in this method and the global supported orientations from either the Info.plist or the application delegate, then the view will rotate. Before the rotation the shouldAutomaticallyForwardRotationMethods method is queried. If YES (the default), then all children will receive the will and didRotateTo... methods as well as the parent (and they in turn will forward it to their children).
My solution (until there is a more eloquent one) is to query the last child view controller during the supportedInterfaceOrientations method and return its value. This lets me rotate some areas while keeping others portrait only. I realize it is fragile, but I don't see another way that doesn't involve complicating things with event calls, callbacks, etc.
If you are using UINavigationController, you have to implement shouldAutorotate and supportedInterfaceOrientations in subclass of UINavigationController.
These are able to control by two steps, if shouldAutorotate returns YES then effective supportedInterfaceOrientations. It's a very nice combination.
This example, my mostly views are Portrait except CoverFlowView and PreviewView.
The CoverFlowView transfer to PreviewView, PreviewView wants to follow CoverFlowCView's rotation.
#implementation MyNavigationController
-(BOOL)shouldAutorotate
{
if ([[self.viewControllers lastObject] isKindOfClass:NSClassFromString(#"PreviewView")])
return NO;
else
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
if ([[self.viewControllers lastObject] isKindOfClass:NSClassFromString(#"CoverFlowView")])
return UIInterfaceOrientationMaskAllButUpsideDown;
else
return UIInterfaceOrientationMaskPortrait;
}
...
#end
my solution : subclassed UINavigationController and set it as window.rootViewController
the top viewcontroller of the hierarchy will take control of the orientation , some code examples : subclassed UINavigationController
The answers here pointed me in the correct direction although I couldn't get it to work by just cut and pasting because I am using UINavigationControllers inside of a UITabBarController. So my version in AppDelegate.m looks something like this, which will work for UITabBarControllers, UINavigationControllers or UINavigationControllers within a UITabBarController. If you are using other custom containment controllers, you would need to add them here (which is kind of a bummer).
- (UIViewController*)terminalViewController:(UIViewController*)viewController
{
if ([viewController isKindOfClass:[UITabBarController class]])
{
viewController = [(UITabBarController*)viewController selectedViewController];
viewController = [self terminalViewController:viewController];
}
else if ([viewController isKindOfClass:[UINavigationController class]])
{
viewController = [[(UINavigationController*)viewController viewControllers] lastObject];
}
return viewController;
}
- (NSUInteger)application:(UIApplication *)application
supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
UIViewController* viewController = [self terminalViewController:window.rootViewController];
if (viewController)
orientations = [viewController supportedInterfaceOrientations];
return orientations;
}
Another key thing to note is that you must override supportedInterfaceOrientations in your UIViewController subclasses or it will default to what you specified in your Info.plist.
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.
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
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;
}
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.