Rotation only in one ViewController Rotation only in one ViewController xcode xcode

Rotation only in one ViewController


I'd recommend using supportedInterfaceOrientationsForWindow in your appDelegate to allow rotation only in that specific view controller, ex:

Swift 4/Swift 5

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {    // Make sure the root controller has been set    // (won't initially be set when the app is launched)    if let navigationController = self.window?.rootViewController as? UINavigationController {        // If the visible view controller is the        // view controller you'd like to rotate, allow        // that window to support all orientations        if navigationController.visibleViewController is SpecificViewController {            return UIInterfaceOrientationMask.all        }         // Else only allow the window to support portrait orientation        else {            return UIInterfaceOrientationMask.portrait        }    }    // If the root view controller hasn't been set yet, just    // return anything    return UIInterfaceOrientationMask.portrait}

Note that if that SpecificViewController is in landscape before going to a portrait screen, the other view will still open in landscape. To circumvent this, I'd recommend disallowing transitions while that view is in landscape.


Swift 3

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {    // Make sure the root controller has been set    // (won't initially be set when the app is launched)    if let navigationController = self.window?.rootViewController as? UINavigationController {        // If the visible view controller is the        // view controller you'd like to rotate, allow        // that window to support all orientations        if navigationController.visibleViewController is SpecificViewController  {            return Int(UIInterfaceOrientationMask.All.rawValue)        }        // Else only allow the window to support portrait orientation        else {            return Int(UIInterfaceOrientationMask.Portrait.rawValue)        }    }    // If the root view controller hasn't been set yet, just    // return anything    return Int(UIInterfaceOrientationMask.Portrait.rawValue)}


You can also do it in a protocol oriented way.Just create the protocol

protocol CanRotate {}

Add the the same 2 methods in the AppDelegate in a more "swifty" way

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {    if topViewController(in: window?.rootViewController) is CanRotate {        return .allButUpsideDown    } else {        return .portrait    }}func topViewController(in rootViewController: UIViewController?) -> UIViewController? {    guard let rootViewController = rootViewController else {        return nil    }    if let tabBarController = rootViewController as? UITabBarController {        return topViewController(in: tabBarController.selectedViewController)    } else if let navigationController = rootViewController as? UINavigationController {        return topViewController(in: navigationController.visibleViewController)    } else if let presentedViewController = rootViewController.presentedViewController {        return topViewController(in: presentedViewController)    }    return rootViewController}

And in every ViewController that you want a different behaviour, just add the protocol name in the definition of the class.

class ViewController: UIViewController, CanRotate {}

If you want any particular combination, they you can add to the protocol a variable to override

protocol CanRotate {    var supportedInterfaceOrientations: UIInterfaceOrientationMask}


Sometimes when you're using a custom navigation flow (that may get really complex) the above-mentioned solutions may not always work. Besides, if you have several ViewControllers that need support for multiple orientations it may get quite tedious.

Here's a rather quick solution I found. Define a class OrientationManager and use it to update supported orientations in AppDelegate:

class OrientationManager {    static var landscapeSupported: Bool = false}

Then in AppDelegate put the orientations you want for that specific case:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {        if OrientationManager.landscapeSupported {            return .allButUpsideDown        }        return .portrait    }

Then in the ViewControllers that you want to have multiple navigations update the OrientationManager:

override func viewDidAppear(_ animated: Bool) {    super.viewDidAppear(animated)    OrientationManager.landscapeSupported = true}

Also, don't forget to update it once again when you'll be exiting this ViewController:

override func viewWillDisappear(_ animated: Bool) {    super.viewWillDisappear(animated)    OrientationManager.landscapeSupported = false    //The code below will automatically rotate your device's orientation when you exit this ViewController    let orientationValue = UIInterfaceOrientation.portrait.rawValue    UIDevice.current.setValue(orientationValue, forKey: "orientation")}

Hope this helps!

Update:

You may just want to add a static func to your Orientation Support Manager class:

    static func setOrientation(_ orientation: UIInterfaceOrientation) {        let orientationValue = orientation.rawValue        UIDevice.current.setValue(orientationValue, forKey: "orientation")        landscapeSupported = orientation.isLandscape    }

Then you can call this function whenever you need to set the orientation back to portrait. That will also update the static landscapeSupported value:

OSM.setOrientation(.portrait)