Search code examples
iosswiftorientationportrait

How to lock orientation just for one view controller?


Can I set a portrait orientation and lock orientation just in one controller?

I did try:

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

override func shouldAutorotate() -> Bool{
    return false
}

but it doesn't help me. Must I to add anything else?


Solution

  • This code should work:

        override func supportedInterfaceOrientations() -> Int {
            return Int(UIInterfaceOrientationMask.Portrait.rawValue)
        }
    
        override func shouldAutorotate() -> Bool{
            return false
        }
    
        override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
            return UIInterfaceOrientation.Portrait
        }
    

    If it is now working for you, then I suppose your controller is in some another controller(UINavigationController, UITabBarController, UISplitViewController). In this case you need to use this code in that parent controller.

    If your navigation controller contain more than one view controller, and you need to disable orientation only for some of them, then you need to inherit UINavigationController class and write there something like:

    class NavigationController: UINavigationController {
    
        var shouldRotate: Bool = true
    
        override func supportedInterfaceOrientations() -> Int {
            return shouldRotate ? Int(UIInterfaceOrientationMask.Portrait.rawValue) : Int(UIInterfaceOrientationMask.All.rawValue)
        }
    
        override func shouldAutorotate() -> Bool{
            return shouldRotate
        }
    }
    

    Then in controller that you need to disable orientation you can disable it for your navigation controller:

    class ViewController: UIViewController {
    
        var lastControllerRotationStatus: Bool?
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
    
            if let navigationController = self.navigationController as? NavigationController {
                lastControllerRotationStatus = navigationController.shouldRotate
                navigationController.shouldRotate = false
            }
        }
    
        override func viewDidDisappear(animated: Bool) {
            super.viewDidDisappear(animated)
    
            if let navigationController = self.navigationController as? NavigationController {
                navigationController.shouldRotate = lastControllerRotationStatus ?? true
            }
        }
    }
    

    But remember, that you need to restore old rotation status after your controller will be pushed out navigation controller. In this example I'm saving rotation status before changing it, and restoring it after controller disappeared. Also you can use some other approach. For example you can overload UINavigationController method popViewController, and there set shouldRotate to false.

    The same approach with variable setting from controller you can use for controlling rotation from AppDelegate method application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int

    Then you do not need to inherit from navigation controller.

    Your AppDelegate class code will look like:

    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
        var shouldRotate = true
        func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
    
            return shouldRotate ? Int(UIInterfaceOrientationMask.All.rawValue) : Int(UIInterfaceOrientationMask.Portrait.rawValue)
    
        }
    
    }
    

    And your controller code will look like:

    class ViewController: UIViewController {
    
        var lastControllerRotationStatus: Bool?
    
        override func viewWillAppear(animated: Bool) {
            super.viewWillAppear(animated)
    
            if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
                lastControllerRotationStatus = appDelegate.shouldRotate
                appDelegate.shouldRotate = false
            }
        }
    
        override func viewDidDisappear(animated: Bool) {
            super.viewDidDisappear(animated)
    
            if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
                appDelegate.shouldRotate = lastControllerRotationStatus ?? true
            }
        }
    }