overriding shouldAutorotate not working in Swift 3
Asked Answered
P

6

31

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?

Politick answered 4/11, 2016 at 0:40 Comment(7)
What does your supportedInterfaceOrientations look like?Evangelist
@Evangelist I edited the question adding thatPolitick
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.Evangelist
@Evangelist 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 controllerPolitick
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).Evangelist
shouldAutorotate is still there, but instead of a function, it is now a var. And what you have in your code seems correct. I think Matt's suggestion is what you need ...Allotrope
@Evangelist thanks for the advise, I create a custom class for the NavigationController and I applied the functions I described from my question and it worksPolitick
P
45

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

Politick answered 4/11, 2016 at 16:27 Comment(5)
but what if you only want a specific UIViewController not to rotate and not the entire navigation stack? This answer seems like a better one: stackoverflow.com/a/39805665Auntie
@RoyShilkrot It is ok, the goal of the question was how to prevent the rotation of one view controller inside a navigation controller, not how to prevent a specific view controller inside a entire navigation stackPolitick
Works nicely in conjunction with @Thuggish Nuggets observation below - so two upvotesHinder
This did not work until checking Requires full screen in the General tab of the app. With that, the Thuggish Nuggets code above should not be necessary.Lessee
amazing great !Mairemaise
A
11

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)

}
Aquilar answered 7/9, 2017 at 7:12 Comment(7)
This works for me, but the accepted answer is much cleaner and also works. Is there a specific scenario where the accepted answer is not possible and only this works?Goggle
This works for me; the accepted answer wasn't working.Thermaesthesia
This works great for me; the best solution, the accepted answer wasn't working very well.Levorotation
Perfect answer!Vitale
This works, but do you find the previous view controller will deinit() ?Resistless
While this solution might work, it uses a private API, which means it may break in future versions; plus, you may have problems with the App Store review guidelines.Intermixture
As stated by @Vym, this method was prone to break in newer versions: in fact it did in 16.0. Using this solution now will fail.Eudemonia
U
4

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.

Uropod answered 16/8, 2018 at 7:15 Comment(0)
P
3

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?)
Poona answered 13/4, 2018 at 2:12 Comment(0)
S
0

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

Stemson answered 5/11, 2019 at 22:6 Comment(1)
This method utilised a private API and was removed in iOS 16.0. Using this solution now will fail.Eudemonia
A
0

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

@objcMembers class YourViewController: UIViewController
{
    override var shouldAutorotate: Bool { return true }
    ...
    init() {}
    ...
 }
Alkali answered 20/2, 2022 at 17:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.