我想将所有viewcontroller的朝向锁定为纵向,除了其中一个,当它被推送时总是在landscapeRight中。我已经尝试了许多解决方案,使用UINavigationController
扩展,覆盖supportedInterfaceOrientations
和shouldAutorotate
,但没有运气。
我已经找到了解决方案,目前它正在工作。
-
在每个视图控制器上,你应该把这段代码只支持所需的旋转(在这个例子中是景观):
override var shouldAutorotate: Bool { return true } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return UIInterfaceOrientationMask.landscapeRight } override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .landscapeRight }
在另一个实现相同的方法,但纵向。
-
为
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
}