Rotation only in one ViewController

后端 未结 13 1867
我在风中等你
我在风中等你 2020-12-05 03:20

I am trying to rotate one view while all other views (5) are fixed to portrait. The reason is that in that one view I want the user to watch pictures which he saved before.

相关标签:
13条回答
  • 2020-12-05 04:02

    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)
    }
    
    0 讨论(0)
  • 2020-12-05 04:08

    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)
    
    0 讨论(0)
  • 2020-12-05 04:10

    Swift 5

    Another answer, this one covers the isBeingDismissed case.

    In AppDelegate:

        func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
            if
                let vvc = navigationController?.visibleViewController,
                vvc is YOURViewControllerClassName &&
                !vvc.isBeingDismissed
            {
                return UIInterfaceOrientationMask.landscape
            } else {
                return UIInterfaceOrientationMask.portrait
            }
        }
    
    0 讨论(0)
  • 2020-12-05 04:15

    This is for Swift 3 and Swift 4. You can use the follow code in your AppDelegate.swift :

    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        guard let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
         (rootViewController.responds(to: Selector(("canRotate")))) else{
            // Only allow portrait (standard behaviour)
            return .portrait;
        }
        // Unlock landscape view orientations for this view controller
        return .allButUpsideDown;
    }
    
    private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
        guard rootViewController != nil else { return nil }
    
        guard !(rootViewController.isKind(of: (UITabBarController).self)) else{
            return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
        }
        guard !(rootViewController.isKind(of:(UINavigationController).self)) else{
            return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
        }
        guard !(rootViewController.presentedViewController != nil) else{
            return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
        }
        return rootViewController
    }
    

    you can learn more in the original post: http://www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in-ios-slash-swift/

    0 讨论(0)
  • 2020-12-05 04:15

    SWIFT 4

    For UITabBarController can we use this line of code in AppDelegate.swift.

    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if let tabBarController = window?.rootViewController as? UITabBarController {
            if let tabBarViewControllers = tabBarController.viewControllers {
                if let projectsNavigationController = tabBarViewControllers[1] as? UINavigationController {
                    if projectsNavigationController.visibleViewController is PickerViewController //use here your own ViewController class name {
                        return .all
                    }
                }
            }
        }
        return .portrait
    }
    
    0 讨论(0)
  • 2020-12-05 04:16

    I just faced a very similar problem where I wanted to present a video player in portrait and landscape mode whereas the rest of the app is portrait only. My main problem was that when I dismissed the video vc in landscape mode the presenting vc was only briefly in landscape mode.
    As pointed out in the comment to @Lyndsey Scott's answer this can be circumvented by disallowing transitions while in landscape mode, but by combining this and this I've found a better and more generic solution (IMO). This solution allows rotation in all vc where you put canRotate(){} and doesn't rotate the presenting vc.

    Swift 3:
    In AppDelegate.swift:

    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
            if (rootViewController.responds(to: Selector(("canRotate")))) {
                // Unlock landscape view orientations for this view controller if it is not currently being dismissed
                if !rootViewController.isBeingDismissed{
                    return .allButUpsideDown
                }
            }
        }
    
        // Only allow portrait (standard behaviour)
        return .portrait
    }
    
    private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
        if (rootViewController == nil) {
            return nil
        }
        if (rootViewController.isKind(of: UITabBarController.self)) {
            return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
        } else if (rootViewController.isKind(of: UINavigationController.self)) {
            return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
        } else if (rootViewController.presentedViewController != nil) {
            return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
        }
        return rootViewController
    }
    

    In each view controller where rotation should be allowed:

    func canRotate(){}
    
    0 讨论(0)
提交回复
热议问题