Rotation only in one ViewController

2019-01-23 17:44发布

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. I guess this is possible but so far I couldn't figure out how to achieve that. Can anyone help or give me a hint? I am programming that in Swift running on iOS8

9条回答
你好瞎i
2楼-- · 2019-01-23 17:45

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
}
查看更多
疯言疯语
3楼-- · 2019-01-23 17:46

You can also do it in a protocol oriented way. Just create the protocol

protocol CanRotate {

}

Add the the same 2 methods in the AppDelegate in a more "swifty" way

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if topViewController(in: window?.rootViewController) is CanRotate {
        return .allButUpsideDown
    } else {
        return .portrait
    }
}


func topViewController(in rootViewController: UIViewController?) -> UIViewController? {
    guard let rootViewController = rootViewController else {
        return nil
    }

    if let tabBarController = rootViewController as? UITabBarController {
        return topViewController(in: tabBarController.selectedViewController)
    } else if let navigationController = rootViewController as? UINavigationController {
        return topViewController(in: navigationController.visibleViewController)
    } else if let presentedViewController = rootViewController.presentedViewController {
        return topViewController(in: presentedViewController)
    }
    return rootViewController
}

And in every ViewController that you want a different behaviour, just add the protocol name in the definition of the class.

class ViewController: UIViewController, CanRotate {}

If you want any particular combination, they you can add to the protocol a variable to override

protocol CanRotate {
    var supportedInterfaceOrientations: UIInterfaceOrientationMask
}
查看更多
贪生不怕死
4楼-- · 2019-01-23 17:51

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/

查看更多
叼着烟拽天下
5楼-- · 2019-01-23 17:54

I'd recommend using supportedInterfaceOrientationsForWindow in your appDelegate to allow rotation only in that specific view controller, ex:

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

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 4

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let navigationController = self.window?.rootViewController as? UINavigationController {
        if navigationController.visibleViewController is DetailsTableViewController {
            return UIInterfaceOrientationMask.all
        } else {
            return UIInterfaceOrientationMask.portrait
        }
    }
    return UIInterfaceOrientationMask.portrait
}
查看更多
Rolldiameter
6楼-- · 2019-01-23 17:55

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!

查看更多
smile是对你的礼貌
7楼-- · 2019-01-23 17:58

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
}
查看更多
登录 后发表回答