To support differing orientations in different view controllers, you will need to do a few things. First, you need to check all the checkboxes for orientations you want to support in your target's General settings tab.
Second, anytime you call presentViewController
or dismissViewController
in your app, the UIApplicationDelegate
method application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask
will be called. You can use this method to restrict (or allow) specific orientations each time a new view controller is presented or dismissed. Unfortunately, it isn't as simple as just returning a UIInterfaceOrientationMask
here. You will need to find the view controller that is going to be showing on screen and return the orientations that it supports. Here is an example of this:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
guard let window = window, let rootViewController = window.rootViewController else {
return UIDevice.currentDevice().userInterfaceIdiom == .Pad ? .All : .AllButUpsideDown // iOS defaults
}
// Let the view controller being shown decide what orientation it wants to support. This method will be called anytime a new view controller is presented on screen.
return findVisibleViewController(rootViewController: rootViewController).supportedInterfaceOrientations()
}
/// Searches the view hierarchy recursively and finds the view controller that is currently showing.
private func findVisibleViewController(rootViewController rootViewController: UIViewController) -> UIViewController {
if let presentedViewController = rootViewController.presentedViewController {
// Search for a modal view first.
return self.findVisibleViewController(rootViewController: presentedViewController)
} else if
let navigationController = rootViewController as? UINavigationController,
let visibleViewController = navigationController.visibleViewController {
// Then search navigation controller's views to find its visible controller.
return self.findVisibleViewController(rootViewController: visibleViewController)
} else if let splitViewController = rootViewController as? UISplitViewController {
// Then try the split view controller. This will be the true root view controller. Use the master here since the detail just shows web views.
return self.findVisibleViewController(rootViewController: splitViewController.viewControllers[0])
} else {
// Guess we found the visible view controller, because none of the other conditions were met.
return rootViewController
}
}
findVisibleViewController(_:)
is an example from one of my projects and is tailored to the exact view controller hierarchy in my app. You will need to edit this for your own app in a way that makes sense for your hierarchy.
Third, you will need to implement supportedInterfaceOrientations()
for most, if not all, of your view controllers.
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return // portrait, landscape, or combinations of those.
}
Finally, this only handles situations where you presented or dismissed something modally. For show (push) segues, the orientation of the navigation controller will be used for every new view controller pushed onto the stack. If you need more fine grained control here, you will need to force the orientation to happen. Here is an example of that:
// Some other view had the screen in landscape, so force the view to return to portrait
UIDevice.currentDevice().setValue(UIInterfaceOrientation.Portrait.rawValue, forKey: "orientation")