仅将一个视图控制器的方向锁定为横向,其余方向锁定为纵向



我想将所有viewcontroller的朝向锁定为纵向,除了其中一个,当它被推送时总是在landscapeRight中。我已经尝试了许多解决方案,使用UINavigationController扩展,覆盖supportedInterfaceOrientationsshouldAutorotate,但没有运气。

我已经找到了解决方案,目前它正在工作。

  1. 在每个视图控制器上,你应该把这段代码只支持所需的旋转(在这个例子中是景观):

    override var shouldAutorotate: Bool {
        return true
    }
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.landscapeRight
    }
    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .landscapeRight
    }
    

    在另一个实现相同的方法,但纵向。

  2. UINavigationController创建扩展

    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return (self.topViewController?.supportedInterfaceOrientations)!
    }
    open override var shouldAutorotate: Bool {
        return true
    }
    

注意:也在项目的目标中启用所有所需的支持方向。

我想在横向模式下显示的唯一一个控制器是模态呈现的

如果使用导航控制器来表示视图,您将会遇到困惑。例如,我们通常通过调用导航控制器实例函数(如performSegueWithIdentifier:sender:pushViewController:animated:)来利用导航控制器来处理添加视图。

push不会像你希望的那样起作用。

和segue可能也不会工作,特别是如果在IB中你创建的segue从导航控制器!

无论如何,如果你以某种方式成功地覆盖了"父"导航控制器的方向,你可能会遇到边缘情况,你可能会使用一些可能会在任何更新中失去支持的粗略的东西。

也就是说,我找到的解决方法是:

步骤1

使用presentViewController:animated:completion:显示景观右视图控制器:

// assuming you're using IB and Main bundle
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let landscapeViewController = storyboard.instantiateViewController(withIdentifier: "LandscapeViewControllerStoryboardID")
self.present(landscapeViewController, animated: true, completion: {
    print("landscapeViewController presented")
})
步骤2

添加以下覆盖到您的landscapeViewController实际上现在工作:

/* override the preferredInterfaceOrientationForPresentation for a view controller
that is intended to be presented full screen in a specific orientation.
https://developer.apple.com/reference/uikit/uiviewcontroller */
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .landscapeRight
}
步骤3(可选)

所有这些工作,仍然有一些奇怪的,当你解散你的landscapeViewController:它现在是横向的。

这是因为导航控制器运行良好。换句话说,现在轮到导航控制器来强制改变方向了,强制它回到原来的样子。

为了做到这一点,您需要在 present landscapeViewController之前存储设备的方向。在显示landscapeViewController的视图控制器中,我将其存储在一个实例变量中:
let ratio = self.view.bounds.width / self.view.bounds.height
if (ratio > 1) { // horizontal/landscape
    self.currentOrientationIsPortrait = false // read by navigation controller when dismissing full screen view player
} else {
    self.currentOrientationIsPortrait = true // read by navigation controller when dismissing full screen view player
}

然后,我在我的navigationController类的首选方向重写中测试视图控制器实例的值。比方说我用来显示landscapeViewController的视图控制器叫做presentingViewController:

// execution order: during visibileViewController's dismissal
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    get {
        if visibleViewController != nil {
            // check if landscapeViewController is being dismissed
            if (visibleViewController as? LandscapeViewController) != nil {
                // check if the top view controller is one that tracks its orientation (currently only presentingViewController)
                if let presentingViewController = self.viewControllers.last as? PresentingViewController {
                    if presentingViewController.currentOrientationIsPortrait {
                        return .portrait // TODO should we not support portraitUpsideDown?
                    }
                }
            }
            // otherwise, return whatever
            return visibleViewController!.preferredInterfaceOrientationForPresentation
        }
        // otherwise, return whatever
        return super.preferredInterfaceOrientationForPresentation
    }
}

,宾果。(希望)

编辑

别忘了把这段代码放到其他ViewControllers中:

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .portrait
}

最新更新