2
votes

I am trying to prevent rotation (lock it to say, portrait) in a specific VC that is embedded in a navigation controller.

I am currently doing this:

To UINavigationController

extension UINavigationController {
    public override func supportedInterfaceOrientations() -> Int {
        return visibleViewController.supportedInterfaceOrientations()
    }
}

In my VC:

class ViewController: UIViewController {
    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Landscape.rawValue)
    }
}

However, I have issues when we go to another VC (embedded in another nav controller) is presented which supports both landscape and portrait. Suppose, the user rotates in the new screen to landscape. And clicks back to go to original screen. The app is now presented in landscape as opposed to portrait defined in its supportedInterfaceOrientations override. How do I prevent this erroneous behaviour?

I read in iOS 11, we should use viewWillTransition(to:with:) to handle rotation (and locking as well). In UIViewController documentation

“As of iOS 8, all rotation-related methods are deprecated. Instead, rotations are treated as a change in the size of the view controller’s view and are therefore reported using the viewWillTransition(to:with:) method. When the interface orientation changes, UIKit calls this method on the window’s root view controller. That view controller then notifies its child view controllers, propagating the message throughout the view controller hierarchy.”

Can you give directions on how to achieve it?

2

2 Answers

2
votes

You can use this cool utility that I've been using.

struct AppUtility {

    static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {

        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }
    }   

    /// OPTIONAL Added method to adjust lock and rotate to the desired orientation
    static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {

        self.lockOrientation(orientation)

        UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
    }
}

You can also rotate your screen and at the same time, lock it to that orientation. I hope this helps!

0
votes

You can use supportedInterfaceOrientationsFor

Define this in your AppDelegate

var restrictRotation = Bool()

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if restrictRotation {
        return .portrait
    }
    else {
        return .all
    }
}

Put below code in your ViewController

func restrictRotation(_ restriction: Bool) {
    let appDelegate = UIApplication.shared.delegate as? AppDelegate
    appDelegate?.restrictRotation = restriction
}

call above function in your ViewController ViewwillAppear like this.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.restrictRotation(true) // TRUE MEANS ONLY PORTRAIT MODE
              //OR
    self.restrictRotation(false) // FALSE MEANS ROTATE IN ALL DIRECTIONS
}