I have this app I am working on and I need ALL my view controllers but one to be in portrait. The single one view controller that is special I need it to be able to rotate t
I'm having the same issue with an app and after days of experimentation I came up with a solution which is not very nice but it works for now. I'm using the delegate method application:supportedInterfaceOrientationsForWindow:
within the appdelegate.
I created a test project and put it here on github (including a GIF which shows the result...)
// note: it's not in swift but I hope it helps anyways
I had the same issue, finally found a solution to open the modal view controller in another UIWindow, and it worked smoothly.
Stack - iOS8 - prevent rotation on presenting viewController
For code: https://github.com/OrenRosen/ModalInWindow
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;
if (secondController.isPresented)
return UIInterfaceOrientationMaskAll;
else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}
And for Swift
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {
if self.window?.rootViewController?.presentedViewController? is SecondViewController {
let secondController = self.window!.rootViewController.presentedViewController as SecondViewController
if secondController.isPresented {
return Int(UIInterfaceOrientationMask.All.toRaw());
} else {
return Int(UIInterfaceOrientationMask.Portrait.toRaw());
}
} else {
return Int(UIInterfaceOrientationMask.Portrait.toRaw());
}
}
For more details check this link
Awesome question and awesome answer provided by @ZaEeM ZaFaR! Combining his answer with this led me to a great and more generic solution.
The drawback of the first answer is that you have to manage the variable isPresented
in every view controller that allows rotations. Furthermore, you have to expand the check and cast in supportedInterfaceOrientationsForWindow
for every vc that allows rotation.
The drawback of the second answer is that it doesn't work; it also rotates the presenting vc when dismissing the presented vc.
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(){}
Swift 3.0 OR Above, Just check "isBeingDismissed" property of presented view controller. Below is sample code, This is will rotate presenting view controller to portrait mode immediately after presented view controller is dismissed.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController)
{
if rootViewController.canRotateVC == true
{
if baseVC.isBeingDismissed == false
{
return .allButUpsideDown
}
}
}
return .portrait}
you can get topController by below code:
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 }
We have an app deployed that has a landscape controller which presents a portrait-only view controller. Was reviewed by Apple on iOS 8. We are only overriding supportedInterfaceOrientations.
It's worth noting that we found lots of differences between betas 3,4,and 5. In the end we had to wait for the GM before making a concerted effort to update our app for iOS 8.
You need to be very careful in iOS 8 to make sure that you don't do this:
[self dismissViewControllerAnimated:YES completion:nil]
[self presentViewController:vc animated:YES completion:nil]
If the outgoing vc is portrait, and the incoming one is landscape, some view frames can end up very messed up. Present the incoming vc in the completion block of the dismiss call instead.
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:vc animated:YES completion:nil]
}];