Rotation only in one ViewController

后端 未结 13 1866
我在风中等你
我在风中等你 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 03:52

    With everyone's ideas I wrote the most elegant way to do it I think.

    Result:

        func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
            return (UIApplication.getTopViewController() as? Rotatable == nil) ? .portrait : .allButUpsideDown
        }
    

    Add this extension to your project which will always be useful not only for this:

    extension UIApplication {
    
        class func getTopViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
            if let nav = base as? UINavigationController {
                return getTopViewController(base: nav.visibleViewController)
            }
    
            if let tab = base as? UITabBarController {
                if let selected = tab.selectedViewController {
                    return getTopViewController(base: selected)
                }
            }
    
            if let presented = base?.presentedViewController {
                return getTopViewController(base: presented)
            }
    
            return base
        }
    
    }
    

    Create the protocol:

    protocol Rotatable {}
    

    And implement it:

    class ViewController: UIViewController, Rotatable {
    }
    
    0 讨论(0)
  • 2020-12-05 03:53

    Use the shouldAutorotate and the supportedInterfaceOrientations method in the ViewController you want to display in landscape and portrait mode:

    This method should override the storyboard-settings.

    override func shouldAutorotate() -> Bool {
        return true
    }
    
    override func supportedInterfaceOrientations() -> Int {
        return UIInterfaceOrientation.Portrait.rawValue | UIInterfaceOrientation.LandscapeLeft.rawValue | UIInterfaceOrientation.LandscapeRight.rawValue
    }
    
    0 讨论(0)
  • 2020-12-05 03:57

    Just wanted to share my solution as someone who has spent too much time rotating one view controller in the app:

    var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { get }
    

    overriding this UIViewController method helped me do what I need.

    1. On the view controller that you want to rotate do this for landscape left rotation:

    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return UIInterfaceOrientation.landscapeLeft }

    1. Make sure you enable rotation in the desired directions from the project settings:

    1. And add this to AppDelegate to disable other screens' rotation:

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

    0 讨论(0)
  • 2020-12-05 03:58

    None of these answers worked for me. Fundamentally, AppDelegate's method does not allow specification on which viewController. So either the topMost ViewController is rotatable, in which case the whole view controller hierarchy gets rotated, or nothing gets rotated.

    However, I did find a promising answer in Child View Controller to Rotate While Parent View Controller Does Not

    It references https://developer.apple.com/library/archive/qa/qa1890/_index.html

    0 讨论(0)
  • 2020-12-05 03:59

    Swift 5 using Marker protocol

    Combined version of several answers here, done in what I think is a more readable/elegant implementation. (Derived from earlier answers here, not original work by me!)

    protocol RotatableViewController {
        // No content necessary, marker protocol
    }
    
    class MyViewController: UIViewController, RotatableViewController {
        // normal content... nothing more required
    }
    
    extension AppDelegate {
    
        func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
            guard
                let rootVc = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController),
                rootVc.isBeingDismissed == false,
                let _ = rootVc as? RotatableViewController
            else {
                return .portrait  // Some condition not met, so default answer for app
            }
            // Conditions met, is rotatable:
            return .allButUpsideDown
        }
    
    
        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
        }
    }
    
    0 讨论(0)
  • 2020-12-05 04:01

    Swift 3: Add code to 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
                    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
        }
    

    Then :

    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
    
        override func viewWillDisappear(_ animated : Bool) {
            super.viewWillDisappear(animated)
    
            if (self.isMovingFromParentViewController) {
                UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
            }
        }
    
        func canRotate() -> Void {}
    
    }
    

    http://www.jairobjunior.com/blog/2016/03/05/how-to-rotate-only-one-view-controller-to-landscape-in-ios-slash-swift/

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