【问题标题】:Restrict Rotation in Tab Bar View Controllers限制选项卡栏视图控制器中的旋转
【发布时间】:2014-11-26 04:53:53
【问题描述】:

更新 2

在我的 UITabBarController 子类中,我尝试添加:

-(void) tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {

        NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];

}

现在,每次我选择标签项时,设备都会完美地旋转到纵向模式。但是,现在我可以在选择 (a) 时旋转设备,并且设备将旋转到横向模式。如何阻止设备旋转?

我相信我的选项卡控制器子类中的这种方法是造成这种情况的原因:

- (BOOL)shouldAutorotate {

    if(self.selectedIndex == 0)
    {
        return NO;
    }

    return [self.viewControllers.lastObject shouldAutorotate];
}

如果我返回“NO”,当我在视图控制器中时,我无法旋转,但当我选择它时,它不会自动旋转到纵向。如果我返回“YES”,我可以在视图控制器中旋转,但是当我选择它时,它会自动旋转为纵向。


我的应用中有一个自定义标签栏控制器,其层次结构如下:

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

我希望视图控制器 (a) 只能在纵向模式下查看,视图控制器 (b) 和 (c) 可以在所有方向上查看,但上下颠倒。现在,我可以单独对每个视图控制器执行此操作,但是当我在 (b) 处于横向模式时出现问题,并选择 (a) 的选项卡项,然后以横向模式显示 a,看起来不好的。如何确保标签栏(或视图控制器)检查是否可以在当前方向查看要选择的视图控制器?

如果需要,这里是我的 (a) 代码,它自己将其限制为纵向模式:

- (BOOL) shouldAutorotate
{
    return NO;
}

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

更新

我已将它添加到视图控制器 (a),但我的视图中间出现了一个黑色方块,并且导航栏中的标题不再居中。

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];


    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];


}

【问题讨论】:

    标签: ios objective-c uiviewcontroller rotation uitabbarcontroller


    【解决方案1】:

    自 iOS 7.0 起,UITabBarController 支持通过- (NSUInteger)tabBarControllerSupportedInterfaceOrientations:(UITabBarController *)tabBarController 进行方向转发。

    在您切换到另一个选项卡并处于此特定选项卡不支持的界面方向之前,它的效果很好。

    不幸的是,tabbar 控制器在这种情况下不会强制旋转,唯一的方法是使用私有 API。

    注意:当从仅纵向选项卡切换回支持任何方向的选项卡时,我使用attemptRotationToDeviceOrientation 将界面旋转到设备方向。

    这是我解决问题的方法:

    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
    

    我将示例应用程序放在 Github 上 https://github.com/pronebird/TabBarOrientationExample

    【讨论】:

    • 感谢您的回答,但这并不能回答我的问题。
    • @Jacob 以何种方式无法回答您的问题?您使用了错误的枚举,请切换到正确的枚举。
    • 当在选项卡控制器中选择它时,我看不到在一个视图控制器中更改我的返回类型如何影响另一个视图控制器中的旋转。
    • @Jacob 如果您将标签栏向前旋转事件发送给子控制器,那么 UIKit 将从子控制器而不是标签栏本身获取所需的方向。其次,您可以尝试在控制器 A 的 viewWillAppear: 中使用 [UIApplication setStatusBarOrientation:animated:] 来强制特定方向。
    • 另外,您的问题似乎与stackoverflow.com/questions/2689598/…重复
    【解决方案2】:

    我曾经为这个确切的问题使用过一种解决方法。这个想法是继承UITabBarController 并将其delegate 设置为自身。 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.它迫使 iOS 以某种方式设置正确的方向。

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

    请注意,它可能依赖于某些实现细节,并且将来可能会停止工作。

    编辑:您还应该在 UITabBarController 子类中实现 supportedInterfaceOrientationsshouldAutorotate。你应该在你想要保持纵向的视图控制器中返回YES in -shouldAutorotate。否则在标签栏中选择时不会从横向旋转到纵向。

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

    【讨论】:

    • 这对我不起作用,只有状态栏旋转到纵向位置...
    • 可能是因为您在shouldAutorotate 中返回了NO。查看编辑后的答案。
    • 正如我在编辑的问题中所说,如果我在 shouldAutorotate 中返回 YES,我可以在选择视图控制器时简单地旋转设备,它将旋转到横向模式而不是严格保持纵向。
    • 如果您在此 VC 中实现的 supportedInterfaceOrientations 中返回正确的值,则它不应旋转。至少它对我有用(将设备旋转到横向后,VC 保持纵向)。
    • 根据您的建议进行更改后,当我旋转设备时,它仍然会旋转。
    【解决方案3】:

    很简单,创建UITabBarController的子类,实现委托方法

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

    【讨论】:

    • 这不会让用户仍然选择选项卡。有没有办法可以检查方向,如果不支持当前方向,则旋转设备,然后不能返回 yes?
    猜你喜欢
    • 2015-10-04
    • 2017-11-15
    • 1970-01-01
    • 2011-02-13
    • 1970-01-01
    • 2019-06-24
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    相关资源
    最近更新 更多