Launching into portrait-orientation from an iPhone

2019-01-30 00:15发布

问题:

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.


回答1:

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:

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.



回答2:

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
}


回答3:

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


回答4:

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


回答5:

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


回答6:

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



回答7:

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;

    }

}


回答8:

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.



回答9:

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!



回答10:

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


回答11:

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.



回答12:

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



回答13:

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