使用横向时UIWindow的大小错误

时间:2014-09-25 11:28:08

标签: ios objective-c iphone landscape uiwindow

我有一个空的应用程序,没有涉及故事板或xib。我希望有一个隐藏的状态栏,只支持横向。同样,我不想仅在代码中进行更改,也不要触摸Info.plist。

问题

我创建了一个带有控制器的UIWindow,该控制器表示唯一支持的方向是横向。在这种情况下,我的UIWindow是在纵向模式的维度中创建的,并且不会旋转。预期的结果将是一个完全是青色的屏幕。

Broken UIWindow

这是我的代表:

#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

这是我的控制者:

#import "AppViewController.h"

@implementation AppViewController

- (BOOL)shouldAutorotate {
  return YES;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
  return UIInterfaceOrientationLandscapeLeft;
}

- (BOOL)prefersStatusBarHidden {
  return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskLandscape;
}

@end

到目前为止我尝试了什么

如果我在调用makeKeyAndVisible之后设置了rootViewController,那么一切似乎都在起作用。

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

仍有一些问题。首先,我不喜欢这样,因为它似乎非常脆弱。第二个问题是,在一个更复杂的应用程序中,将GLKViewController设置为rootViewController,我得到以下结果(预计左边没有黑色区域):

Broken GLKViewController

看起来状态栏没有及早隐藏。几个手势识别器处于活动状态,在GLKViewController中单击黑色区域会产生以下日志消息:

  

2014-09-25 13:20:42.170 StackOverflowExample [6971:107907]意外的零窗口   _UIApplicationHandleEventFromQueueEvent,_windowServerHitTestWindow:UIClassicWindow:0x7fa20b805e00; frame =(0 0; 375 667);   userInteractionEnabled = NO; gestureRecognizers = NSArray:   0x7fa20b80a620; layer = UIWindowLayer:0x7fa20b806890

我还执行了各种其他更改,例如附加一个空的UIViewController并将我的视图添加为子视图。在这种情况下,我的视图看起来正确,但窗口仍然使用错误的尺寸。

如果我没有覆盖视图控制器中的supportedInterfaceOrientations方法,那么一切都会正确旋转。但那当然不是我想要的。

6 个答案:

答案 0 :(得分:24)

当您从人像模式运行风景应用时,UIScreen在iOS 8中具有人像范围(仅当您没有此应用时)在app开关面板中,因为iOS 8会产生一些缓存)。即使显示makeKeyAndVisible窗口也不会改变它的框架。但它会根据[UIScreen mainScreen].bounds可用的方向更改AppViewController

#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

因此,请在[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;
}

我认为这是iOS 8的bug。

答案 1 :(得分:8)

我有一个类似的问题,对于一个只限肖像的应用程序。

我通过在实例化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;
}

在您的情况下,您应该在UIInterfaceOrienationLandscapeLeft方法中使用setStatusBarOrientation:animated:(或右)。

希望它对你有所帮助。

答案 2 :(得分:2)

就个人而言,上述解决方案均无效。我最后为我的主xib中的窗口设置了“隐藏”为YES,如下所示:unexpected nil window in _UIApplicationHandleEventFromQueueEvent, _windowServerHitTestWindow

答案 3 :(得分:0)

添加启动屏幕时解决了这个问题,您只能通过向info.plist添加额外的属性来实现

我自己有这个问题,我不确定你是否可以通过代码添加它,我只能设法使用info.plist +启动屏幕xib文件

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

实际上我不认为你必须添加一个xib文件,如果只有密钥(有任何值)在plist中可以使用它。

答案 4 :(得分:0)

此处或其他地方发布的解决方案均不适合我。

但是,我发现这个问题显然不会出现在Storyboard中,因此另一种解决方案是远离xib。 (遗憾的是,这也让苹果公司不太可能认真对待这个问题。)

答案 5 :(得分:0)

您可以通过仅添加单行来旋转UIWindow。 您可以为UIWindow设置rootController。例如:

fileprivate(set) var bottonOverlayWindow = UIWindow()

self.bottonOverlayWindow.rootViewController = self; 

//'self'将在其上添加UIWindow视图的ViewController。因此,每当ViewController更改方向时,您的窗口视图也会更改其方向。

让我知道您是否遇到任何问题。