How to lock orientation of one view controller to portrait mode only in Swift

后端 未结 16 2055
梦谈多话
梦谈多话 2020-11-22 12:07

Since my app got support for all orientation. I would like to lock only portrait mode to specific UIViewController.

e.g. assume it was Tabbed Application and when Si

相关标签:
16条回答
  • 2020-11-22 12:18

    bmjohns -> You are my life saviour. That is the only working solution (With the AppUtility struct)

    I've created this class:

    class Helper{
        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")
            }
    
        }
    }
    

    and followed your instructions, and everything works perfectly for Swift 3 -> xcode version 8.2.1

    0 讨论(0)
  • 2020-11-22 12:20

    Things can get quite messy when you have a complicated view hierarchy, like having multiple navigation controllers and/or tab view controllers.

    This implementation puts it on the individual view controllers to set when they would like to lock orientations, instead of relying on the App Delegate to find them by iterating through subviews.

    Swift 3, 4, 5

    In AppDelegate:

    /// set orientations you want to be allowed in this property by default
    var orientationLock = UIInterfaceOrientationMask.all
    
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
            return self.orientationLock
    }
    

    In some other global struct or helper class, here I created AppUtility:

    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")
            UINavigationController.attemptRotationToDeviceOrientation()
        }
    
    }
    

    Then in the desired ViewController you want to lock orientations:

     override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        AppUtility.lockOrientation(.portrait)
        // Or to rotate and lock
        // AppUtility.lockOrientation(.portrait, andRotateTo: .portrait)
        
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // Don't forget to reset when view is being removed
        AppUtility.lockOrientation(.all)
    }
    

    If iPad or Universal App

    Make sure that "Requires full screen" is checked in Target Settings -> General -> Deployment Info. supportedInterfaceOrientationsFor delegate will not get called if that is not checked.

    0 讨论(0)
  • 2020-11-22 12:24

    Swift 4

    AppDelegate

    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")
        }
    }
    

    Your ViewController Add Following line if you need only portrait orientation. you have to apply this to all ViewController need to display portrait mode.

    override func viewWillAppear(_ animated: Bool) {
    AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
        }
    

    and that will make screen orientation for others Viewcontroller according to device physical orientation.

    override func viewWillDisappear(_ animated: Bool) {
            AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.all)
    
        }
    
    0 讨论(0)
  • 2020-11-22 12:25

    This is a generic solution for your problem and others related.

    1. Create auxiliar class UIHelper and put on the following methods:

        /**This method returns top view controller in application  */
        class func topViewController() -> UIViewController?
        {
            let helper = UIHelper()
            return helper.topViewControllerWithRootViewController(rootViewController: UIApplication.shared.keyWindow?.rootViewController)
        }
    
        /**This is a recursive method to select the top View Controller in a app, either with TabBarController or not */
        private func topViewControllerWithRootViewController(rootViewController:UIViewController?) -> UIViewController?
        {
            if(rootViewController != nil)
            {
                // UITabBarController
                if let tabBarController = rootViewController as? UITabBarController,
                    let selectedViewController = tabBarController.selectedViewController {
                    return self.topViewControllerWithRootViewController(rootViewController: selectedViewController)
                }
    
                // UINavigationController
                if let navigationController = rootViewController as? UINavigationController ,let visibleViewController = navigationController.visibleViewController {
                    return self.topViewControllerWithRootViewController(rootViewController: visibleViewController)
                }
    
                if ((rootViewController!.presentedViewController) != nil) {
                    let presentedViewController = rootViewController!.presentedViewController;
                    return self.topViewControllerWithRootViewController(rootViewController: presentedViewController!);
                }else
                {
                    return rootViewController
                }
            }
    
            return nil
        }
    

    2. Create a Protocol with your desire behavior, for your specific case will be portrait.

    protocol orientationIsOnlyPortrait {}

    Nota: If you want, add it in the top of UIHelper Class.

    3. Extend your View Controller

    In your case:

    class Any_ViewController: UIViewController,orientationIsOnlyPortrait {
    
       ....
    
    }
    

    4. In app delegate class add this method:

     func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
            let presentedViewController = UIHelper.topViewController()
            if presentedViewController is orientationIsOnlyPortrait {
                return .portrait
            }
            return .all
        }
    

    Final Notes:

    • If you that more class are in portrait mode, just extend that protocol.
    • If you want others behaviors from view controllers, create other protocols and follow the same structure.
    • This example solves the problem with orientations changes after push view controllers
    0 讨论(0)
  • 2020-11-22 12:25

    For a new version of Swift try this

    override var shouldAutorotate: Bool {
        return false
    }
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.portrait
    }
    
    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return UIInterfaceOrientation.portrait
    }
    
    0 讨论(0)
  • 2020-11-22 12:26

    Swift 3 & 4

    Set the supportedInterfaceOrientations property of specific UIViewControllers like this:

    class MyViewController: UIViewController {
    
        var orientations = UIInterfaceOrientationMask.portrait //or what orientation you want
        override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        get { return self.orientations }
        set { self.orientations = newValue }
        }
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        //...
    }
    

    UPDATE

    This solution only works when your viewController is not embedded in UINavigationController, because the orientation inherits from parent viewController.
    For this case, you can create a subclass of UINavigationViewController and set these properties on it.

    0 讨论(0)
提交回复
热议问题