Restrict Rotation in Tab Bar View Controllers

你说的曾经没有我的故事 提交于 2019-12-09 22:28:44

问题


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"];


}

回答1:


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




回答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;
}



回答3:


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


来源:https://stackoverflow.com/questions/27141594/restrict-rotation-in-tab-bar-view-controllers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!