UINavigationController:在每次转换后显示embedded的视图控制器不同的方向?

这是StackOverflow常见的问题,但没有其他解决scheme的工作。 许多也是几年前写的。

这里是一些考虑的职位:

  • UINavigationController中的viewControllers有可能有不同的方向吗?

  • 在UINavigationController中只支持一个视图的横向

  • UINavigationController中的viewControllers有可能有不同的方向吗?

  • 为什么使用UINavigationController时无法强制横向?

  • 如何强制在iOS 8视图控制器方向?

我们在UINavigationController中embedded了几个视图控制器:A,B,C,D。

A,B使用肖像。

C,D使用景观。

A是根控制器。

假设B被推到A.这是因为B是肖像。 但是,当C被推到B上时,由于类文档状态,屏幕不会旋转:

通常,系统只在窗口的根视图控制器或呈现的视图控制器上调用此方法以填充整个屏幕; 子视图控制器使用父视图控制器为其提供的窗口部分,不再直接参与关于支持哪些旋转的决定。

因此,在自定义的UINavigationController中重写supportedInterfaceOrientations并不会有帮助,因为在embedded式控制器的转换中没有查询它。

实际上,我们需要一种方式来强制转型时的方向转变,但似乎没有支持的方法。

下面是我们如何覆盖UINavigationController(扩展仅用于debugging目的,因为明显的扩展不应该用于覆盖):

 extension UINavigationController { override open var shouldAutorotate: Bool { return true } override open var supportedInterfaceOrientations : UIInterfaceOrientationMask { return visibleViewController?.supportedInterfaceOrientations ?? UIInterfaceOrientationMask.landscapeRight } } 

在embedded式视图控制器中,我们尝试设置像这样的方向:

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

总而言之,目标是:

1)显示embedded在不同方向的UINavigationController中的视图控制器。

2)VC转换应该产生适当的方向变化(例如,从C-> B的出现应该产生肖像,从D-> C出现应该产生景观,从B→C推出应该产生景观,从A-> B推动应该产生肖像)。

如果可以强制UINavigationController进入一个方向(使用公开支持的方法),一个可能的解决scheme可能是在显示新的视图控制器时强制方向。 但是这似乎也不可能。

build议?

步骤1

子类UINavigationController

 class LandscapeNavigationController: UINavigationController { public var vertical: Bool = true override var shouldAutorotate: Bool { get { return true }} override var supportedInterfaceOrientations: UIInterfaceOrientationMask { get { return (vertical) ? .portrait : .landscapeLeft }} override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get { return (vertical) ? .portrait : .landscapeLeft }} } 

第2步

针对不同的方向使用不同的UINavigationController 。 是的,在先前的UINavigationController上推新的UINavigationController基本上是模态的,但过渡看起来不错。

带有2个导航控制器的故事板

为了更加方便,请使用用户定义的运行属性来控制LandscapeNavigationController的方向。

运行时属性

第3步

添加一个pop方法来处理现在的模式UIViewController 后退button。

 @IBAction func doBack(_ sender: UIBarButtonItem) { if let navigationController = navigationController { navigationController.dismiss(animated: true, completion: { }) } } 

在行动

请注意视图C上的顶部底部标签是如何正确布置的。

动画
↻重播animation


►在GitHub上find这个解决scheme和Swift Recipes的更多细节。