解雇模态视图控制器时如何保持显示视图控制器的方向?

时间:2014-06-15 12:40:45

标签: ios iphone uiviewcontroller swift screen-rotation

我有这个应用程序,我正在努力,我需要所有的视图控制器,但一个是肖像。 单一的视图控制器是特殊的,我需要它能够旋转到手机的任何方向。

为此,我以模态方式呈现它(未嵌入NavigationController中)

所以(例如)我的结构是这样的:

  • 窗口 - 肖像
    • 根视图控制器(UINavigationController - Portrait)
      • 主视图控制器(UIViewController - Portrait)
        • 详细信息视图控制器(UIViewController - Portrait)
        • 模态视图控制器(UIVIewController - All)

现在,当我在横向位置解除模态视图控制器时,我的父视图控制器也会旋转,即使它不支持该方向。

应用中的所有UIViewControllersUINavigaionControllers都继承了实现这些方法的相同通用类:

override func supportedInterfaceOrientations() -> Int
{
    return Int(UIInterfaceOrientationMask.Portrait.toRaw())
}

我的模态视图控制器再次覆盖此方法,它看起来像这样:

override func supportedInterfaceOrientations() -> Int
{
    return Int(UIInterfaceOrientationMask.All.toRaw())
}

更新1

看起来这只发生在iOS8 Beta上。 有人知道视图控制器的旋转是否有变化,或者这只是测试版中的错误吗?

9 个答案:

答案 0 :(得分:18)

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
    SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;

    if (secondController.isPresented)
        return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}

对于Swift

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {

    if self.window?.rootViewController?.presentedViewController? is SecondViewController {

        let secondController = self.window!.rootViewController.presentedViewController as SecondViewController

        if secondController.isPresented {
            return Int(UIInterfaceOrientationMask.All.toRaw());
        } else {
            return Int(UIInterfaceOrientationMask.Portrait.toRaw());
        }
    } else {
        return Int(UIInterfaceOrientationMask.Portrait.toRaw());
    }

}

有关详细信息,请查看此link

答案 1 :(得分:7)

我在使用应用程序时遇到了同样的问题,经过几天的实验后,我想出了一个不太好的解决方案,但它现在可以使用了。我在appdelegate中使用委托方法application:supportedInterfaceOrientationsForWindow:

我创建了一个测试项目并将其here on github(包括显示结果的GIF ...)

//注意:它不是很快但我希望它能帮助

答案 2 :(得分:4)

经过多次实验,我确信这是一个"功能" iOS 8。

如果你仔细想想,这很有道理,因为它已经存在了很长时间。

  • 在iOS 4中,可以在更改标签栏控制器和导航控制器中的视图控制器时以及在显示/取消控制器时强制应用程序旋转。

  • 然后在iOS 6中,除了在呈现/取消视图控制器时(除了我在许多答案中解释过,例如this one)之外,不可能强制进行应用程序轮换。

  • 现在,在iOS 8中,我猜想根本不可能强制进行应用程序轮换(启动时除外)。它可以偏好某个方向,因此一旦它处于该方向,它将保持在那里,但它不能强制应用程序进入该方向。

    相反,您的视图控制器应该"适应"。有几个WWDC 2014视频专注于"适应",现在我开始明白这就是为什么这么重要的一个原因。

    编辑:在种子4中,看起来这个功能(强制演示和解雇时的轮换)正在返回!

答案 3 :(得分:3)

我们部署的应用程序具有横向控制器,该控制器提供仅限纵向的视图控制器。在iOS 8上由Apple审核。我们只是覆盖supportedInterfaceOrientations。

值得注意的是,我们发现3,4和5之间存在很多差异。最后我们不得不等待GM,然后再努力更新我们的iOS 8应用程序。

你需要在iOS 8中非常小心,以确保你不要这样做:

[self dismissViewControllerAnimated:YES completion:nil]
[self presentViewController:vc animated:YES completion:nil]

如果传出的vc是纵向的,并且传入的vc是横向的,则某些视图帧最终会非常混乱。而是将收到的vc呈现在解雇通话的完成块中。

[self dismissViewControllerAnimated:YES completion:^{
    [self presentViewController:vc animated:YES completion:nil]
}];

答案 4 :(得分:2)

这实际上更容易,可以在没有任何其他属性的情况下完成(这是li的示例):

AVPlayerViewController

答案 5 :(得分:1)

在根视图控制器中,尝试添加:

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

为我工作。

答案 6 :(得分:1)

@ZaEeM ZaFaR提供了很棒的问题和很棒的答案!将他的答案与this相结合,使我得到了一个更好,更通用的解决方案。

第一个答案的缺点是你必须在每个允许旋转的视图控制器中管理变量isPresented。此外,您必须扩展检查并在supportedInterfaceOrientationsForWindow中为每个允许旋转的vc进行强制转换。

第二个答案的缺点是它不起作用;当解除所呈现的vc时,它还旋转呈现的vc。

此解决方案允许在所有放置canRotate(){}的vc中旋转,并且不会旋转呈现的vc。

斯威夫特3:
在AppDelegate.swift中:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
        if (rootViewController.responds(to: Selector(("canRotate")))) {
            // Unlock landscape view orientations for this view controller if it is not currently being dismissed
            if !rootViewController.isBeingDismissed{
                return .allButUpsideDown
            }
        }
    }

    // Only allow portrait (standard behaviour)
    return .portrait
}

private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
    if (rootViewController == nil) {
        return nil
    }
    if (rootViewController.isKind(of: UITabBarController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
    } else if (rootViewController.isKind(of: UINavigationController.self)) {
        return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
    } else if (rootViewController.presentedViewController != nil) {
        return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
    }
    return rootViewController
}

在每个允许旋转的视图控制器中:

func canRotate(){}

答案 7 :(得分:0)

  

Swift 3.0或以上,   只需检查呈现的视图控制器的“isBeingDismissed”属性即可。   下面是示例代码,这将在呈现的视图控制器被解除后立即将视图控制器呈现为纵向模式。

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController)
{
  if rootViewController.canRotateVC == true
  {
    if baseVC.isBeingDismissed == false
    {
      return .allButUpsideDown
    }
  }
}

  return .portrait}
  

你可以通过以下代码获得topController:

  private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController?{
if (rootViewController == nil) { return nil }if (rootViewController.isKind(of: (UITabBarController).self))
{
  return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
}
else if (rootViewController.isKind(of:(UINavigationController).self))
{
  return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
}
else if (rootViewController.presentedViewController != nil)
{
  return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController }

答案 8 :(得分:-1)

我有同样的问题,终于找到了在另一个UIWindow中打开模态视图控制器的解决方案,并且它运行顺利。

堆栈 - iOS8 - prevent rotation on presenting viewController

代码: https://github.com/OrenRosen/ModalInWindow