31
votes

I'm trying to prevent rotation on one UIViewController and I can't achieve that.

I'm doing something like this:

open override var shouldAutorotate: Bool {
    get {
        return false
    }
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    get {
        return .portrait
    }
}

And the UIViewControler stills rotating. The UIViewController is inside a UINavigationController opened modally.

I have looked a lot of questions from here and none answers works for me.

In Swift 2 I used to override shouldAutorotate but in Swift 3 that function doesn't exist anymore.

How can I do that in Swift 3 what I used to do in Swift 2?

6
What does your supportedInterfaceOrientations look like?matt
@matt I edited the question adding thatpableiros
Thanks. Okay, so if this is a presented view controller, it should appear only in portrait and stay there. If that's not happening, there must be more to the story. Can you describe how this view controller is presented? Prove to me that it is a fullscreen top-level presented view controller.matt
@matt The view controller is presented modally via a bar button item tapped and the view controller is inside a navigation controller, I don't know if is not possible to prevent rotation on a modal view controllerpableiros
If you present a view controller that itself is inside a navigation controller, that is not a presented view controller. The navigation controller is the presented view controller. So the problem would be that your view controller's settings here are irrelevant; it is the navigation controller that is the presented view controller, so it gets to determine the rotation (if I understand you correctly).matt

6 Answers

45
votes

I don't know why is a vote to close the question if I can reproduce this behavior a lots of times. The UIViewController is inside a UINavigationController opened modally.

This is what I did to solve the problem.

I create this class and I set to the UINavigationController that containt the UIViewController that I want to prevent to rotate

class NavigationController: UINavigationController { 

    override var shouldAutorotate: Bool {
        return false
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .portrait
    }

}

And thats it, it works for me

11
votes

Add this code to AppDelegate.swift

var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return self.orientationLock
}

struct AppUtility {
    static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }

    static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
        self.lockOrientation(orientation)
        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
    }
}

Add to the viewcontroller that you want to force an orientation:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    //let value = UIInterfaceOrientation.landscapeLeft.rawValue
    //UIDevice.current.setValue(value, forKey: "orientation")


    AppDelegate.AppUtility.lockOrientation(.landscapeLeft)

}
4
votes

For me, the voted answer didn't work. Instead,

override open var shouldAutorotate: Bool {
    return false
}

override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return UIApplication.shared.statusBarOrientation
}

Those codes work. Confirmed in Swift 4.

3
votes

I found that iOS 11 wasn't calling these methods at all unless I had implemented the following UIApplicationDelegate method in my AppDelegate class:

application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?)
0
votes

iOS 11, Swift 5

The new secret sauce is to add this in viewDidLoad()

UIDevice.current.setValue(self.preferredInterfaceOrientationForPresentation.rawValue, forKey: "orientation")

Also be sure to override preferredInterfaceOrientationForPresentation to return your preferred orientation:

override var preferredInterfaceOrientationForPresentation : UIInterfaceOrientation { return UIInterfaceOrientation.portrait }

Found the answer here: https://nunoalexandre.com/2018/08/24/forcing-an-orientation-in-ios

0
votes

Swift 5 Answer - this is how you do it now in 2022

@objcMembers class YourViewController: UIViewController
{
    override var shouldAutorotate: Bool { return true }
    ...
    init() {}
    ...
 }