UIWindow with wrong size when using landscape orientation
Asked Answered
U

6

18

I have an empty application and there is no storyboard or xib involved. I want to have a hidden status bar and support only landscape orientation. Again, I wan't to make those changes only within code and don't touch the Info.plist.

Problem

I create a UIWindow with a controller that says the only supported orientation is landscape. In that case my UIWindow is created in the dimension of portrait mode and doesn't rotate. The expected result would be a screen that is completely cyan.

Broken UIWindow

This is my delegate:

#import "AppDelegate.h"
#import "AppViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  self.window.backgroundColor = [UIColor cyanColor];
  self.window.rootViewController = [[AppViewController alloc] init];
  [self.window makeKeyAndVisible];
  return YES;
}

@end

This is my controller:

#import "AppViewController.h"

@implementation AppViewController

- (BOOL)shouldAutorotate {
  return YES;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
  return UIInterfaceOrientationLandscapeLeft;
}

- (BOOL)prefersStatusBarHidden {
  return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskLandscape;
}

@end

What I've tried so far

If I set the rootViewController after calling makeKeyAndVisible everything seems to work at first.

self.window.backgroundColor = [UIColor cyanColor];
[self.window makeKeyAndVisible];
self.window.rootViewController = [[AppViewController alloc] init];

There are still some issues. First of all I don't like this since it seems to be very fragile. Second problem is that in a more complex application that sets a GLKViewController as the rootViewController I get the following result (expected would be no black area on the left):

Broken GLKViewController

It looks like the status bar is not hidden early enough. Several gesture recognizers are active and in the GLKViewController and clicking on the black area yields the following log message:

2014-09-25 13:20:42.170 StackOverflowExample[6971:107907] unexpected nil window in _UIApplicationHandleEventFromQueueEvent, _windowServerHitTestWindow: UIClassicWindow: 0x7fa20b805e00; frame = (0 0; 375 667); userInteractionEnabled = NO; gestureRecognizers = NSArray: 0x7fa20b80a620; layer = UIWindowLayer: 0x7fa20b806890

I also performed various other changes, like attaching an empty UIViewController and adding my view as a sub-view. In that case my view looks correct but the window is still using the wrong dimensions.

Everything rotates correct if I do not override the supportedInterfaceOrientations methods in my view controller. But that is of course not what I want.

Unemployable answered 25/9, 2014 at 11:28 Comment(0)
R
26

When you run landscape app from portrait mode UIScreen has portrait bounds in iOS 8 (only if you haven't this app in app switch panel, as iOS 8 makes some cache). Even displaying window with makeKeyAndVisible doesn't change it's frame. But it changes [UIScreen mainScreen].bounds according to AppViewController avaliable orientation.

#import "AppDelegate.h"
#import "AppViewController.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  // Portrait bounds at this point
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

  self.window.backgroundColor = [UIColor cyanColor];
  self.window.rootViewController = [[AppViewController alloc] init];
  [self.window makeKeyAndVisible];
  return YES;
}

@end

So let's change window's frame after [self.window makeKeyAndVisible]

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [UIWindow new];
    self.window.backgroundColor = [UIColor cyanColor];
    self.window.rootViewController = [[AppViewController alloc] init];
    [self.window makeKeyAndVisible];

    // Here it is
    self.window.frame = [UIScreen mainScreen].bounds;
    return YES;
}

I think that it is iOS 8 bug.

Renz answered 25/9, 2014 at 13:51 Comment(2)
Thanks for sharing. I just spent many hours trying to figure out how to do it.Millennial
With iOS8.1 and using Swift I needed to add a small fraction to the width and height of the UIWindow to solve my issue as done here : https://mcmap.net/q/393958/-unexpected-nil-window-in-_uiapplicationhandleeventfromqueueevent-_windowserverhittestwindowSelfservice
R
8

I had a similar problem, for a portrait-only app.

I fixed the problem by setting status bar orientation BEFORE instantiate the UIWindow

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Init my stuff
    // ...

    // Prepare window
    [application setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO]; // prevent start orientation bug
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    [self.window makeKeyAndVisible];
    return YES;
}

In your case, you should use UIInterfaceOrienationLandscapeLeft (or Right) in the setStatusBarOrientation:animated: method.

Hope it helps you.

Rice answered 14/10, 2014 at 13:38 Comment(0)
T
2

Personally, none of the solution presented above worked. I finally set "hidden" to YES for the window in my main xib, as first suggested here: unexpected nil window in _UIApplicationHandleEventFromQueueEvent, _windowServerHitTestWindow

Ticktacktoe answered 27/12, 2014 at 13:37 Comment(0)
M
1

You can rotate UIWindow by adding single line only. You can set the rootController for your UIWindow. e.g:

fileprivate(set) var bottonOverlayWindow = UIWindow()

self.bottonOverlayWindow.rootViewController = self; 

// 'self' will the ViewController on which you had added UIWindow view. So whenever you ViewController change the orientation, your window view also change it's orientation.

Let me know if you face any issue.

Mikol answered 13/9, 2019 at 12:31 Comment(0)
G
0

The problem is solved when adding a Launch Screen, which you can only do by adding an extra property to the info.plist

had this problem myself, i'm not sure if you can add it through code though, i only managed to make it work with info.plist + Launch Screen xib file

<key>UILaunchStoryboardName</key>
<string>Launch Screen</string>

Actually i don't think you have to add a xib file, if just the key (with any value) is available in the plist it should work.

Glucinum answered 25/9, 2014 at 11:49 Comment(1)
Didn't do it for me unfortunately.Unemployable
M
0

None of the solutions posted here or elsewhere worked for me.

However, I found that this issue apparently does not occur with Storyboards, so an alternative solution is to move away from xibs. (This fact sadly also makes it unlikely that Apple will take the problem seriously.)

Malm answered 23/10, 2014 at 21:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.