How to maintain presenting view controller's orientation when dismissing modal view controller?

24,542

Solution 1

- (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

Solution 2

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

Solution 3

After much experimentation, I am convinced that this is a "feature" of iOS 8.

If you think about it, this makes perfect sense, because it has been coming for a long time.

  • In, say iOS 4, it was possible to force app rotation when changing view controllers in a tab bar controller and a navigation controller, as well as when presenting/dismissing a controller.

  • Then in iOS 6 it became impossible to force app rotation except when presenting/dismissing a view controller (as I explained in many answers, such as this one).

  • Now, in iOS 8, I conjecture that it will be impossible to force app rotation at all (except at launch). It can prefer a certain orientation, so that once it is in that orientation it will stay there, but it cannot force the app to go into that orientation.

    Instead, your view controller is expected to "adapt". There are several WWDC 2014 videos concentrating on "adaptation", and now I'm starting to understand that this is one reason why this is so important.

    EDIT: In seed 4, it looks like this feature (forcing rotation on presentation and dismissal) is returning!

Solution 4

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]
}];

Solution 5

This is actually easier and can be done without any additional properties (here's an example with AVPlayerViewController):

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        if ([self.window.rootViewController.presentedViewController isKindOfClass: [AVPlayerViewController class]])
            return self.window.rootViewController.presentedViewController.isBeingDismissed ? 
            UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskAll;
        else
            return UIInterfaceOrientationMaskPortrait;
    } else {
        return UIInterfaceOrientationMaskAll;
    }
}
Share:
24,542
Mihai Fratu
Author by

Mihai Fratu

Young but experienced PHP and iOS Developer eager to help others.

Updated on May 03, 2021

Comments

  • Mihai Fratu
    Mihai Fratu about 3 years

    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 to whatever orientation the phone is in.

    To do that I present it modally (not embedded in a NavigationController)

    So (for example) my structure is like this:

    • window - Portrait
      • root view controller (UINavigationController - Portrait)
        • home view controller (UIViewController - Portrait)
          • details view controller (UIViewController - Portrait)
          • .
          • .
          • .
          • modal view controller (UIVIewController - All)

    Now when ever I dismiss my modal view controller in a landscape position my parent view controller is ALSO rotated even though it doesn't support that orientation.

    All UIViewControllers and UINavigaionControllers in the app inherit from the same general classes which have these methods implemented:

    override func supportedInterfaceOrientations() -> Int
    {
        return Int(UIInterfaceOrientationMask.Portrait.toRaw())
    }
    

    My modal view controller overrides this method once again and it looks like this:

    override func supportedInterfaceOrientations() -> Int
    {
        return Int(UIInterfaceOrientationMask.All.toRaw())
    }
    

    Update 1

    It looks like this is happening only on iOS8 Beta. Does someone know if there is something that changed regarding view controller's rotation or is this just a bug in the beta?