UINavigationController:在每次转换后显示具有不同方向的嵌入式视图控制器?

时间:2017-01-02 20:48:17

标签: ios swift uiviewcontroller uinavigationcontroller uikit

这是StackOverflow上的一个常见问题,但其他解决方案都没有奏效。许多人也在几年前写过。

以下是一些考虑的帖子:

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

A,B使用肖像。

C,D使用风景。

A是根控制器。

假设B被推到A.这是有效的,因为B是肖像。但是,当C被推到B上时,屏幕不会旋转,因为类docs状态:

  

通常,系统仅在根视图上调用此方法   窗口的控制器或视图控制器呈现填充   整个屏幕;子视图控制器使用窗口的一部分   由他们的父视图控制器提供给他们,不再   直接参与有关支持轮换的决定。

因此在自定义UINavigationController中覆盖supportedInterfaceOrientations没有帮助,因为在嵌入式控制器中的转换时不会参考它。

实际上,我们需要一种在转换时强制方向更改的方法,但似乎没有支持这种方法。

以下是我们如何覆盖UINavigationController(扩展现在仅用于调试目的,因为显然扩展不应该用于覆盖):

extension UINavigationController {
    override open var shouldAutorotate: Bool {
        return true
    }

    override open var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        return visibleViewController?.supportedInterfaceOrientations ?? UIInterfaceOrientationMask.landscapeRight
    }
}

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

override var shouldAutorotate: Bool {
    return true
}


override var preferredInterfaceOrientationForPresentation : UIInterfaceOrientation {
    return UIInterfaceOrientation.landscapeRight
}


override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.landscapeRight
}

总结一下,目标是:

1)显示嵌入在具有不同方向的UINavigationController内的视图控制器。

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

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

建议?

1 个答案:

答案 0 :(得分:4)

第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基本上是模态的,但过渡看起来不错。

Storyboard with 2 nav controllers

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

Runtime attributes

第3步

添加 pop 方法来处理现在模态UIViewController上的 Back 按钮。

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

在行动中

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

Animation
↻ replay animation

►在GitHub上找到此解决方案,并在Swift Recipes上找到其他详细信息。