Limit rotation in tab bar controllers

UPDATE 2

In my subclass of UITabBarController, I tried adding this:

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

Now, every time I select a tab element, the device works fine in portrait mode. However, now I can rotate the device while (a) is selected, and the device will rotate in landscape mode. How can I stop the rotation of the device?

I believe this method in my subclass of the tab controller calls this:

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

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




I have a custom tab bar controller in my application with the following hierarchy:

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

I want View Controller (a) to be displayed only in portrait mode, and View Controllers (b) and (c) to be displayed in all directions, but upside down. Now I can do this with each view controller separately, but my problem arises when I am in (b) in landscape mode and select a tab element for (a) and then displayed in landscape mode that does not look good. How can I make sure the tab bar (or view controller) checks to see if the current view controller can be viewed in its current orientation?

If necessary, here is my code for (a), which itself restricts it to portrait mode:

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

UPDATE

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

 -(void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait]; [[UIDevice currentDevice] setValue:value forKey:@"orientation"]; } 
+2
ios objective-c rotation uiviewcontroller uitabbarcontroller
Nov 26 '14 at 4:53 on
source share
3 answers

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

It works fine until you switch to another tab, being in an interface orientation that this particular tab does not support.

Unfortunately, the tablet controller does not rotate in this case, and the only way is to use a private API.

Note. I use attemptRotationToDeviceOrientation to rotate the interface to the device orientation when switching from a tab only to a port to a tab that supports any orientation.

This is my approach to the 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 attached a sample application to Github at https://github.com/pronebird/TabBarOrientationExample

+4
Nov 28 '14 at 19:12
source share

I used a workaround once for this exact problem. The idea was to subclass UITabBarController and set its delegate to itself. Then, in the subclass, I made the following โ€œhackโ€: when the controller was selected for portrait only, I pressed and immediately rejected the empty modal VC. This forced iOS to set the correct orientation.

 -(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]; } } 

Please note that it probably depends on some implementation details and may stop working in the future.

EDIT: You must also implement supportedInterfaceOrientations and shouldAutorotate in a subclass of UITabBarController . And you must return YES to -shouldAutorotate in the view controller that you want to leave in the portrait. Otherwise, it will not rotate from landscape to portrait if it is selected in the 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; } 
+1
Nov 28 '14 at 23:43
source share

Its simple, subclass UITabBarController and implement the delegation 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; } } 
0
Nov 28 '14 at 8:10
source share



All Articles