58
votes

The actual title for this question is longer than I can possibly fit:

Launching an app whose root view controller only supports portrait-orientation but which otherwise supports landscape orientations on an iPhone 6 Plus while the home screen is in a landscape orientation results in a limbo state where the app's window is in a landscape orientation but the device is in a portrait orientation.

In short, it looks like this:

When it is supposed to look like this:

Steps to Reproduce:

  1. iPhone 6 Plus running iOS 8.0.

  2. An app whose plist supports all-but-portrait-upside-down orientations.

  3. The root view controller of the app is a UITabBarController.

  4. Everything, the tab bar controller and all its descendent child view controllers return UIInterfaceOrientationMaskPortrait from supportedInterfaceOrientations.

  5. Start at iOS home screen.

  6. Rotate to landscape orientation (requires iPhone 6 Plus).

  7. Cold-launch the app.

  8. Result: broken interface orientations.

I can't think of any other way to enforce a portrait orientation except to disable landscape altogether, which I can't do: our web browser modal view controllers need landscape.

I even tried subclassing UITabBarController and overriding supportedInterfaceOrientations to return the portrait-only mask, but this (even with all the other steps above) did not fix the issue.


Here's a link to a sample project showing the bug.


13
Have you filed a bug to radar?Pichirichi
Justin Miller on Apple Forum suggested the following: "Your information property list should specify the orientations that you are willing to allow your app to launch to (which should correspond to the supported orientations of your initial view controller)."Pichirichi
I loved the way you framed the question.. I was wondering how to put it across. Thanks for saving my day. !!!kirans_6891

13 Answers

79
votes

I had the same issue when launching our app in landscape on an iPhone 6 Plus.

Our fix was to remove landscape supported interface orientations from the plist via project settings:

Removed landscape orientation

and implement application:supportedInterfaceOrientationsForWindow: in the app delegate:

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

Apparently the information in your plist is to specify what orientations your app is allowed to launch to.

38
votes

Setting the statusBarOrientation of the UIApplication seems to work for me. I placed it in the application:didFinishLaunchingWithOptions: method in the app delegate.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    application.statusBarOrientation = UIInterfaceOrientationPortrait;

    // the rest of the method
}
6
votes

This appears to be a bug in iOS 8 when using a UITabBarController as a root view controller. A workaround is to use a mostly vanilla UIViewController as the root view controller. This vanilla view controller will serve as the parent view controller of your tab bar controller:

///------------------------
/// Portrait-Only Container
///------------------------

@interface PortraitOnlyContainerViewController : UIViewController

@end

@implementation PortraitOnlyContainerViewController

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

@end

// Elsewhere, in app did finish launching ...

PortraitOnlyContainerViewController *container = nil;

container = [[PortraitOnlyContainerViewController alloc] 
              initWithNibName:nil 
              bundle:nil];

[container addChildViewController:self.tabBarController];
self.tabBarController.view.frame = container.view.bounds;
[container.view addSubview:self.tabBarController.view];
[self.tabBarController didMoveToParentViewController:container];

[self.window setRootViewController:container];
2
votes

I only want my app to open in landscape mode (and not exhibit the problem you describe above on the iPhone 6 Plus), so I set Landscape (left home button) and Landscape (right home button) as the only orientations allowed in my app's PLIST file. This fixes the orientation problem when my app opens. However, I need my app to support portrait mode for one view only since I display a UIImagePickerController in my app, which Apple requires to be shown in portrait mode on iPhone.

I was able to support portrait for that one view only, while keeping my app opening in landscape mode, by including the following code in AppDelegate:

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {

        return UIInterfaceOrientationMaskAllButUpsideDown;

    } else {

        return UIInterfaceOrientationMaskAll;

    }

}
2
votes

I had a very similar problem. I wanted to force portrait mode everywhere except for playing back videos.

What I did was:

1) to force the app orientation to be in portrait in the AppDelegate:

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if ([window.rootViewController.presentedViewController isKindOfClass:[MPMoviePlayerViewController class]])
    {
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

2) launching an empty modal view controller fixed the problem in my case. I launch it in the viewDidLoad of the first view controller that is on the root of my NavigationViewController (the first view controller visible after the application launches):

- (void)showAndHideNamelessViewControllerToFixOrientation {
    UIViewController* viewController = [[UIViewController alloc] init];
    [self presentViewController:viewController animated:NO completion:nil];
    [viewController dismissViewControllerAnimated:NO completion:nil];
}
1
votes

Please try the following code. Probably this problem caused by size of keywindow on landscape launch.

// in application:didFinishLaunchingWithOptions: ...

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[self.window setFrame:[[UIScreen mainScreen] bounds]]; //<- ADD!!
1
votes

No luck for me the workaround by Jared using a generic container view controller. I've already subclassed tab bar controller with supportedInterfaceOrientations with no luck as well. Regardless of orientation of the 6+ after launch the tab bar's window is reporting frame = (0 0; 736 414)

So far the only workaround I've found is to force the window frame after makeKeyAndVisible

[self.window makeKeyAndVisible]; self.window.frame = CGRectMake(0, 0, MIN(CGRectGetWidth(self.window.frame), CGRectGetHeight(self.window.frame)), MAX(CGRectGetWidth(self.window.frame), CGRectGetHeight(self.window.frame)));

1
votes

I got same bug on my app, I figured it out with this solution

Firstly it didn't work but after some dig I have to do it on initial controller after splash screen.

Answer is OjbC language let me update it to Swift

override var shouldAutorotate: Bool {
    return true
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

Don't forget that should on the initial view controller.

0
votes

For myself, I was having the same issue as jaredsinclair, but subclassing a UIViewController with the supportedInterfaceOrientations method was not solving the issue. Instead I did exactly what he did in my appDidFinishLaunching method of my AppDelegate and added my UITabBarController as a child to a normal UIViewController rather than his subclass and it worked!

0
votes

I'm in the same situation, and doing [self.window setFrame:...] doesn't work for me.

Adding the following at the end of application:didFinishLaunchingWithOptions is the only thing I've found that works. It makes the screen blink and isn't exactly clean and efficient.

I added this at the end of application:didFinishLaunchingWithOptions:

UIViewController *portraitViewController = [[UIViewController alloc] init];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController];
[self.navController presentViewController:nc animated:NO completion:nil];
[self.navController dismissViewControllerAnimated:NO completion:nil];  
[UIViewController attemptRotationToDeviceOrientation];
0
votes

I had a similar issue is with my app runs both in landscape and portrait with a UITabBarController as root view controller.

Whenever the app was launched when in Landscape mode, the view was incorrect.

All I had to do: - remove rootview controller assignment in the XIB. - Manually add it in once the app is launched:


  • (void)applicationDidFinishLaunching:(UIApplication *)application { application.statusBarHidden = YES;

    [self.window setRootViewController:self.tabBarController];


That fixed the problem.

0
votes

Just Remove All the items in Supported interface orientation except what you want (i need only Portrait) in info.plist , it will work for meenter image description here

-1
votes

just call [application setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO]; in app delegate method - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

in fact the device now is UIInterfaceOrientationPortrait after Launching ,if you touch an inputField ,the keyboard is portrait layout