如何在纵向应用程序中以纵向或横向呈现视图控制器

Mus*_*sis 10 uinavigationcontroller device-orientation ios ios8

我有一个iPhone应用程序,其中大多数只是纵向的,但有一个视图控制器(视频播放器屏幕),必须支持纵向和横向(这仅适用于iOS 8).为了达到这个目的,我已经设置了app的plist来支持肖像和两种风景,然后是子类UINavigationController; 在这个子类中我重写

- (BOOL)shouldAutorotate {
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

- (NSUInteger)supportedInterfaceOrientations {

    if ([self.visibleViewController isKindOfClass:[MyVideoPlayerScreen class]]) {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    } else {
        return UIInterfaceOrientationMaskPortrait;
    }

}
Run Code Online (Sandbox Code Playgroud)

大部分都按预期工作:初始屏幕都是纵向的,即使设备转为横向也会保持纵向.视频播放器最初呈现时:

MyVideoPlayerScreen *newVC = [MyVideoPlayerScreen new];
[self.navigationController pushViewController:newVC animated:YES];
Run Code Online (Sandbox Code Playgroud)

也是纵向的,但是当设备转动时它会旋转到横向 - 到目前为止一切都很好.

问题是,如果我将设备转为横向,视频播放器也会出现景观,但是当我通过后退按钮关闭视频播放器屏幕时,底层视图控制器(应该是仅限肖像的)现在是也在景观中.如果我将设备旋转回纵向,则视图控制器也会旋转回纵向,然后从该点开始正确锁定设备.

如何弹出原始视图控制器(应该是仅限肖像),以便在其上方的横向视图控制器弹出时自动返回到纵向?

这个问题已被问过一百万次,但似乎已发布的修复程序都是在iOS 8中无法运行的黑客攻击.

更新:我发现了一个"类型"修复程序,可以在iOS 8中运行.在我的UINavigationController子类中,我处理<UINavigationControllerDelegate>协议.我实现了这个方法:

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {

    if (![viewController isKindOfClass:[MyVideoPlayerScreen class]]) {

        // if the current orientation is not already portrait, we need this hack in order to set the root back to portrait
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
        if (orientation != UIInterfaceOrientationPortrait) {

            // HACK: setting the root view controller to nil and back again "resets" the navigation bar to the correct orientation
            UIWindow *window = [[UIApplication sharedApplication] keyWindow];
            UIViewController *vc = window.rootViewController;
            window.rootViewController = nil;
            window.rootViewController = vc;

        }

    }

}
Run Code Online (Sandbox Code Playgroud)

这至少使UI处于我希望它处于的状态.问题是当顶层视图控制器被关闭并在屏幕外动画时,底层视图控制器仍处于格局中; 然后它突然跳到肖像.不理想,但总比没有好.

更新2:我应该补充说我正在推送第二个视图控制器,如下所示:

ViewControllerPortraitLandscape *newVC = [ViewControllerPortraitLandscape new];
[self.navigationController pushViewController:newVC animated:YES];
Run Code Online (Sandbox Code Playgroud)

更新3:好的,这是完全可行的,适用于iOS 6及更高版本.修复甚至有点意义,虽然它的工作原因似乎不在任何地方的文档中.基本上,在视图控制器中,当设备仍处于横向状态时顶层视图控制器被关闭时,您需要将其重置为纵向,您只需添加以下内容:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}
Run Code Online (Sandbox Code Playgroud)

虽然我的子类UINavigationController完全负责旋转调用,但断点显示在顶层被解除之前supportedInterfaceOrientations底层视图控制器上调用,并且在顶层被解除在导航控制器上调用它.所以我推断这个对视图控制器本身的调用是由iOS制作的,以确定底层视图控制器应该处于什么方向(并且它不会向导航控制器询问这个); 如果它没有被明确覆盖,它将返回全部但倒置的参数,因此iOS只是将它留在原处.

Mus*_*sis 5

事实证明这是一个简单的修复:你可以通过UINavigationController我在这里发布的子类驱动整个过程(即在视图控制器本身中没有实现任何这些旋转方法),除了对于任何需要纵向的视图控制器 -只是,你还需要实现这个:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}
Run Code Online (Sandbox Code Playgroud)

使用断点,您可以看到在上面的推送视图控制器被解除之前调用此方法; iOS可能会使用此调用来确定"显示的"视图控制器应该处于什么方向(在顶级视图控制器被关闭调用导航控制器子类的相同调用).

通过在视图控制器中实现此方法,一切都按预期工作.