UIScreen applicationFrame在横向应用程序启动时返回不正确的矩形(iPhone/iPad)

21

在横屏模式下启动我的iPad应用程序时,无法获取正确的边界。 我在我的Info.plist文件中设置了正确的键,并且我的视图控制器在横向(和纵向)模式下都能正常启动。

在我的applicationDidFinishLaunching:方法中,我通过延迟3秒钟来调用一个选择器,并且该方法调用[[UIScreen mainScreen] applicationFrame],但它返回给我一个纵向框架(即高度>宽度)。

有人知道如何解决这个问题吗?对我来说,这像是一个错误(如果是的话,我会提交反馈),但如果这是预期行为,那么它在哪里记录?


16
从现在开始我能用“incorrectangle”这个词吗? - jbrennan
8个回答

35

我从不依赖于[[UIScreen mainScreen] applicationFrame],特别是在应用启动期间。

在使用代码创建视图时,请使用父视图来设置你的框架大小。

如果你在使用带有“模拟接口元素”的xibs,则它们将被正确调整大小,并且一切都将运作良好。

基于UINavigationController的应用程序

对于基于UINavigationController的应用程序,请直接从self.navigationController.view获取框架大小,不要尝试使用[self loadView]self.view.superview。 UINavigationController使用“隐藏”的子视图来完成其工作--因此直接父视图将无法正常工作。

UINavigationController很特殊,因为在应用程序启动期间,导航控制器会在调用loadView之后调整视图大小。 当自动调整大小开始时,你会得到屏幕底部的一个小余白。

为什么不使用UIScreen

[[UIScreen mainScreen] applicationFrame]无法可靠工作(特别是在横向启动应用程序时)。 我的经验是,视图控制器的interfaceOrientation属性与applicationFrame的方向不匹配。


这非常重要!谢谢。 - coco
这非常有帮助!如果我早些发现它,我会节省很多时间!谢谢! - coder284

14
CGRect bounds = [[UIScreen mainScreen] bounds]; // portrait bounds
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
    bounds.size = CGSizeMake(bounds.size.height, bounds.size.width);
}

6

当视图控制器处于横向模式时,以下是我获取正确CGRect的方法:

CGRect landscapeBounds;
if (self.view.frame.size.width < self.view.frame.size.height)
    landscapeBounds = CGRectMake(self.view.frame.origin.y, self.view.frame.origin.x, self.view.frame.size.height, self.view.frame.size.width);
else
    landscapeBounds = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, self.view.frame.size.height);

6
当您以横向模式持有iPad并启动应用程序时,视图控制器最初会看到纵向视图的边界(尽管方向报告为横向)。然后,视图控制器将在出现之前收到旋转到横向模式的消息。

那么,在消息发送到视图控制器进行旋转后,坐标系会反映新的方向吗?例如,在发送消息后,宽度>高度? - Adam Ritenauer

5

这是设计上的问题。您应该查询您的父视图大小并根据需要进行调整。


你能解释一下为什么要这样设计吗(或者至少猜测一下)?如果屏幕已经旋转,给出不正确的边界似乎对我来说是不合逻辑的。所涉及的“superview”是我的应用程序窗口(我也尝试使用它的框架得到相同的结果)。 - jbrennan
原因是窗口可以独立于屏幕旋转。例如:当一个竖屏应用程序启动YouTube视频时,主窗口仍然保持竖屏状态,但横屏窗口会在其上方动画显示。在动画期间,设备应被视为竖屏还是横屏?(加速度计方向与窗口方向与状态栏方向是分开的) - rpetrich
我也注意到了,这真的很奇怪。谢谢你提醒。 - Daddy
1
我的应用程序窗口在这种情况下是我的超级视图,并且即使它是横向的,它仍然报告纵向边界。非常令人沮丧。但我只需要使用[UIDevice orientation]在需要时交换w + h即可。 - jbrennan
4
不应该使用-[UIDevice orientation]来进行此操作,而应该使用-[UIApplication statusBarOrientation]。在这种情况下,UIDeviceOrientation具有其他没有意义的状态:UIDeviceOrientationUnknownUIDeviceOrientationFaceUpUIDeviceOrientationFaceDown - rpetrich

2

[[UIScreen mainScreen] applicationFrame]会始终返回纵向矩形,即使应用程序处于横向模式。这与UIWindow实际上从不旋转有关,而只是改变rootViewController.view的变换。

要确保,您可以在纵向和横向模式下打印根视图对象,您将看到如下内容:

纵向:

<UIView: 0x96290e0; frame = (0 20; 768 1004); ...

横向排列:

<UIView: 0x96290e0; frame = (0 20; 768 1004); transform = [0, 1, -1, 0, 0, 0]; ...

1

因此,根据苹果的指南,添加一个启动图像并将其后缀命名为-568h。

我不明白为什么任何理智的人都会使系统设置依赖于图形;但是我刚刚测试了一下,它确实起作用了。

这里是我在快速搜索后学到的地方 我没有看到上面的答案,觉得对某些人可能有用。

S


0
我在使用Cordova插件的dismissViewControllerAnimated方法关闭视图时遇到了同样的问题。 我修改了MainViewController中viewWillAppear方法的singingAtom代码,该方法在关闭模态视图后发生了变化大小。
- (void)viewWillAppear:(BOOL)animated
    {
    CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
    UIDeviceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    if (UIDeviceOrientationLandscapeLeft == orientation || 
        UIDeviceOrientationLandscapeRight == orientation)
            {
            if (appFrame.size.width < appFrame.size.height)
                {
                appFrame = CGRectMake(appFrame.origin.y, appFrame.origin.x, appFrame.size.height, appFrame.size.width);
                }
        }
    self.view.frame = appFrame;
    [super viewWillAppear:animated];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接