3

UPDATE 2

In my UITabBarController subclass I tried adding this:

-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; } 

Now, everytime I select a tab item, the device rotates to portrait mode perfectly. However, now I can rotate the device while (a) is selected, and the device will rotate to landscape mode. How can I stop the device from rotating?

I believe this method in my tab controller subclass is what is causing this:

- (BOOL)shouldAutorotate { if(self.selectedIndex == 0) { return NO; } return [self.viewControllers.lastObject shouldAutorotate]; } 

If I return 'NO' I cannot rotate when I'm in the view controller, but when I select it, it does not automatically rotate to portrait. If I return 'YES' I can rotate when I'm in the view controller, but when I select it, it automatically rotates to portrait.


I have a custom Tab Bar Controller in my app with the following hierarchy:

UITabBarController | UINavigationController | | | UIViewController(a) | UINavigationController | | | UIViewController(b) | UINavigationController | UIViewController(c) 

I want View Controller (a) to only be able to be viewed in portrait mode, and View Controllers (b) and (c) to be viewable in all orientations but upside down. Now, I can do this with each view controller individually, but my issue comes in when I am in (b) in landscape mode, and select the tab item for (a), a is then displayed in landscape mode, which does not look good. How can I make sure the tab bar (or the view controller) checks to see if the to-be-selected view controller can be viewed in the current orientation?

If needed, here is my code for (a) that restricts it to portrait mode on its own:

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

UPDATE

I have added this to view controller (a), but I get a black square in the middle of my view, and the title in the nav bar is no longer centered.

-(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; } 

3 Answers 3

7
+50

Since iOS 7.0 UITabBarController supports orientation forwarding via - (NSUInteger)tabBarControllerSupportedInterfaceOrientations:(UITabBarController *)tabBarController.

It works great until you switch to the other tab while being at interface orientation that this particular tab does not support.

Unfortunately tabbar controller does not force the rotation in that case and the only way is to use private API.

Note: I use attemptRotationToDeviceOrientation to rotate interface to device orientation when switching back from portrait only tab to tab that supports any orientation.

This is my approach to problem:

static const NSInteger kPortraitOnlyTabIndex = 1; @interface TabBarController : UITabBarController<UITabBarControllerDelegate> @end @implementation TabBarController - (id)initWithCoder:(NSCoder *)aDecoder { if(self = [super initWithCoder:aDecoder]) { self.delegate = self; } return self; } - (NSUInteger)tabBarControllerSupportedInterfaceOrientations:(UITabBarController *)tabBarController { if(tabBarController.selectedIndex == kPortraitOnlyTabIndex) { return UIInterfaceOrientationMaskPortrait; } return UIInterfaceOrientationMaskAllButUpsideDown; } - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { [UIViewController attemptRotationToDeviceOrientation]; if([self.viewControllers indexOfObject:viewController] == kPortraitOnlyTabIndex) { SEL sel = NSSelectorFromString(@"setOrientation:"); if([[UIDevice currentDevice] respondsToSelector:sel]) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [[UIDevice currentDevice] performSelector:sel withObject:(__bridge id)((void*)UIInterfaceOrientationPortrait)]; #pragma clang diagnostic pop } } } @end 

I put example app on Github at https://github.com/pronebird/TabBarOrientationExample

Sign up to request clarification or add additional context in comments.

13 Comments

Thank you for your answer, but this does not answer my question.
@Jacob in what way it does not answer your question? You use wrong enum, switch to right one.
I don't see how changing my return type in one view controller affects the rotation in another when it is selected in the tab controller.
@Jacob if you make tabbar forward rotation events to child controllers then UIKit will take the desired orientation from child controller instead of tabbar itself. Second, you can try using [UIApplication setStatusBarOrientation:animated:] in viewWillAppear: of controller A to force a particular orientation.
Also, it seems your question is a duplicate of stackoverflow.com/questions/2689598/…
|
2

I used a workaround once for this exact problem. The idea was to subclass UITabBarController and set its delegate to itself. Then in a subclass I did a following "hack": when the portrait-only controller was selected, I pushed and immediately dismissed an empty modal VC. It forced iOS to set the correct orientation somehow.

-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController { UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation; NSInteger currentViewControllerSupportsLandscape = ([viewController supportedInterfaceOrientations] & UIInterfaceOrientationMaskLandscape); if(UIInterfaceOrientationIsLandscape(currentOrientation) && !currentViewControllerSupportsLandscape) { //workaround to force rotating to portrait UIViewController *c = [[UIViewController alloc]init]; [viewController presentViewController:c animated:NO completion:nil]; [viewController dismissViewControllerAnimated:NO completion:nil]; } } 

Note that it's probably dependent on some implementation detail and can possibly stop working in the future.

EDIT: You should also implement supportedInterfaceOrientations and shouldAutorotate in a UITabBarController subclass. And you should return YES in -shouldAutorotate in the view controller you want to stay in portrait. Otherwise it won't rotate from landscape to portrait when selected in tab bar.

- (NSUInteger) supportedInterfaceOrientations { return [self.currentViewController supportedInterfaceOrientations]; } - (BOOL) shouldAutorotate { return [self.currentViewController shouldAutorotate]; } - (UIViewController*) currentViewController { UIViewController* controller = self.selectedViewController; if([controller isKindOfClass:[UINavigationController class]]) { controller = [((UINavigationController*)controller).viewControllers objectAtIndex:0]; } return controller; } 

5 Comments

This does not work for me, only the status bar rotates to the portrait position...
Maybe it's because you return NO in shouldAutorotate. Look at edited answer.
As I said in my edited question, if I return YES in shouldAutorotate, I can simply rotate the device while the view controller is selected, and it will rotate to landscape mode instead of strictly staying in portrait.
It shouldn't rotate if you return proper value in supportedInterfaceOrientations implemented in this VC. At least it works for me (the VC stays in portrait after rotating the device to landscape).
It still rotates when I rotate the device after I have made your suggested changes.
0

Its simple, Create subclass of UITabBarController, and implement delegate method

- (BOOL)tabBarController:(UITabBarController *)tbController shouldSelectViewController:(UIViewController *)viewController { //Check for orientation here if (supported orientation for view controller == [[UIApplication sharedApplication] statusBarOrientation]) { return YES; } else { return NO; } } 

1 Comment

This will not let the user select the tab still, though. Is there a way I can check for the orientation, rotate the device if the current orientation is not supported,can't then return yes?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.