旋转到横向后,iOS 边界发生变化,然后又回到纵向

Posted

技术标签:

【中文标题】旋转到横向后,iOS 边界发生变化,然后又回到纵向【英文标题】:iOS bounds change after rotating to landscape, then back to portrait 【发布时间】:2012-09-13 18:07:44 【问题描述】:

当我的应用程序启动时,我的视图边界的 NSLog 显示如下:

NSLog(@"My view frame: %@", NSStringFromCGRect(self.view.bounds));
My view frame: 0, 0, 320, 548

然后我旋转模拟器并得到以下信息:

NSLog(@"My view frame: %@", NSStringFromCGRect(self.view.bounds));
My view frame: 0, 0, 320, 548

然后当我将模拟器旋转回纵向时,我得到了这个:

NSLog(@"My view frame: %@", NSStringFromCGRect(self.view.bounds));
My view frame: 0, 0, 568, 300

我用来调整元素的两种方法是这些,它们还没有完成,因为我目前正在为新的 iphone 修复它们。

-(void) resizeForLandscape

    newsLabel = (UILabel *)[self.view viewWithTag:50];
    weatherLabel = (UILabel *)[self.view viewWithTag:51];
    sportsLabel = (UILabel *)[self.view viewWithTag:52];
    entertainmentLabel = (UILabel *)[self.view viewWithTag:53];
    videosLabel = (UILabel *)[self.view viewWithTag:54];
    moreLabel = (UILabel *)[self.view viewWithTag:55];

    NSLog(@"resizeForLandscape called");
    webView.frame = CGRectMake(0, 31, self.view.frame.size.width, self.view.frame.size.height - 75);    
    button.frame = CGRectMake(0, 0, image.size.width -30, image.size.height -15);
    myLabel.frame = CGRectMake(230, 100, 80, 21);
    label.frame = CGRectMake(0, 0, self.view.bounds.size.height + 15, 30);

    NSLog(@"My view frame: %@", NSStringFromCGRect(self.view.bounds));
    NSLog(@"my status bar height is %f", [UIApplication sharedApplication].statusBarFrame.size.height);
    NSLog(@"my status bar width is %f", [UIApplication sharedApplication].statusBarFrame.size.width);


    newsLabel.frame = CGRectMake((self.view.bounds.size.height - 346) / 2 + 12, self.view.bounds.size.width - 38, 43, 21);
    weatherLabel.frame = CGRectMake(newsLabel.frame.origin.x + 64, self.view.bounds.size.width - 38, 42, 21);
    sportsLabel.frame = CGRectMake(newsLabel.frame.origin.x + 126, self.view.bounds.size.width - 38, 42, 21);
    entertainmentLabel.frame = CGRectMake(newsLabel.frame.origin.x + 185, self.view.bounds.size.width - 38, 66, 21);
    videosLabel.frame = CGRectMake(newsLabel.frame.origin.x + 269, self.view.bounds.size.width - 38, 42, 21);
    moreLabel.frame = CGRectMake(newsLabel.frame.origin.x + 325, self.view.bounds.size.width - 38, 42, 21);

    spacer1.width = (self.view.bounds.size.height - 346) / 2;
    spacer2.width = 40;
    spacer3.width = 28;
    spacer4.width = 42;
    spacer5.width = 35;
    spacer6.width = 24;


-(void) resizeForPortrait

    newsLabel = (UILabel *)[self.view viewWithTag:50];
    weatherLabel = (UILabel *)[self.view viewWithTag:51];
    sportsLabel = (UILabel *)[self.view viewWithTag:52];
    entertainmentLabel = (UILabel *)[self.view viewWithTag:53];
    videosLabel = (UILabel *)[self.view viewWithTag:54];
    moreLabel = (UILabel *)[self.view viewWithTag:55];

    NSLog(@"resizeForPortrait called");

    webView.frame = CGRectMake(0, 44, self.view.frame.size.width, self.view.frame.size.height -88);
    button.frame = CGRectMake(0, 0, image.size.width, image.size.height);
    myLabel.frame = CGRectMake(145, 152, 80, 21);
    label.frame = CGRectMake(0, 0, 315, 40);

    NSLog(@"My view frame: %@", NSStringFromCGRect(self.view.bounds));

    NSLog(@"my status bar height is %f", [UIApplication sharedApplication].statusBarFrame.size.height);
    NSLog(@"my status bar width is %f", [UIApplication sharedApplication].statusBarFrame.size.width);


    float myWidth = MIN(self.view.bounds.size.height, self.view.bounds.size.width);
    float myHeight = MAX(self.view.bounds.size.height, self.view.bounds.size.width);

    newsLabel.frame = CGRectMake(newsLabel.frame.origin.x, myHeight - 18, 43, 21);
    weatherLabel.frame = CGRectMake(newsLabel.frame.origin.x + 43, myHeight - 18, 42, 21);
    sportsLabel.frame = CGRectMake(newsLabel.frame.origin.x + 97, myHeight - 18, 42, 21);
    entertainmentLabel.frame = CGRectMake(newsLabel.frame.origin.x + 138, myHeight - 18, 66, 21);
    videosLabel.frame = CGRectMake(newsLabel.frame.origin.x + 213, myHeight - 18, 42, 21);
    moreLabel.frame = CGRectMake(newsLabel.frame.origin.x + 258, myHeight - 18, 42, 21);


    spacer1.width = (myWidth - 346) / 2;
    spacer2.width = 20;
    spacer3.width = 18;
    spacer4.width = 25;
    spacer5.width = 28;
    spacer6.width = 14;

调用者:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 

    if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft || toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) 
        [self resizeForLandscape];
     else 
        [self resizeForPortrait];
    


- (void) getOrientationandResize
    
    if (UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) 
        [self resizeForLandscape];
     else 
        [self resizeForPortrait];
    


- (void)viewDidAppear:(BOOL)animated

    [super viewDidAppear:animated];
    [self getOrientationandResize];

我的头快要爆炸了。不仅视图被颠倒了,而且从宽度上抢走了 20 个像素并赋予了高度。任何人都可以向我解释这一点,以及我可以/应该如何对我的视图中的元素进行编码以解释它吗?

我的故事板如下:

我的初步看法:

第一次旋转后(还不错)

旋转回纵向(由于边界值,一切都搞砸了)

【问题讨论】:

我猜你的边界是在窗口边界之前设置的。至于 20px 将成为顶部的状态栏。 从委托轮换时调用了哪些方法?你在使用 IB 吗? 我以为20px是状态栏,但是为什么它只在两次旋转之后才出现呢?它不应该从一开始就在那里吗?另外,作为一个额外的奇怪之处,当我在旋转回到 portait ([UIApplication sharedApplication].statusBarFrame.size.height) 后打印出状态栏高度时,它会说:我的状态栏高度是 568.000000。 出于好奇,宽度是20px吗? 我刚刚测试过,当你旋转它并不会改变状态栏的边界,只是旋转它们 【参考方案1】:

您几乎不应该在willRotateToInterfaceOrientation:duration: 中进行布局。当系统向您发送willRotateToInterfaceOrientation:duration: 时,它尚未将您的视图框架更新为新尺寸。因此,通过咨询self.view.frame,您使用的是当前(旧)方向的框架,不是新(尚未旋转到)方向的框架。

您也不应该在viewDidAppear: 中进行布局,因为当您收到viewDidAppear: 时,您的视图已经在屏幕上。您需要您的视图出现在屏幕上之前进行布局。

您需要以适当的方法进行布局。进行布局的最佳位置是自定义UIView 子类的layoutSubviews 方法。把它放在那里可以让你的视图逻辑与你的控制器逻辑分开。

进行布局的下一个最佳位置是视图控制器的 viewWillLayoutSubviewsviewDidLayoutSubviews 方法。

如果您将布局代码放在layoutSubviewsviewWillLayoutSubviewsviewDidLayoutSubviews 中,系统将自动在您的视图出现在屏幕上之前以及在动画块内调用该方法的自转。在这两种情况下,它都会在向您发送消息之前更新您的视图框架以确保正确的方向。

如果您需要在自动旋转动画开始之前隐藏视图并在之后再次显示它,您可以在willRotateToInterfaceOrientation:duration:didRotateFromInterfaceOrientation: 中执行此操作。

如果您希望在自动旋转期间执行特殊动画,而不是在初始视图布局期间,您可以在 willAnimateRotationToInterfaceOrientation:duration: 中执行此操作,它在自动旋转的动画块内调用。

您可能会发现此答案很有帮助:UIViewController returns invalid frame?

【讨论】:

谢谢,我会试一试并回复您! 是的,viewDidLayoutSubviews 解决了我的问题。 很好的信息来指导正确的做事方式。 (+1)

以上是关于旋转到横向后,iOS 边界发生变化,然后又回到纵向的主要内容,如果未能解决你的问题,请参考以下文章

应用程序启动时锁定为纵向从横向旋转到纵向 (iOS)

iOS 7 旋转设备未检测到横向屏幕边界

iOS App:窗口旋转总是纵向而不是横向

Autodesk Forge Viewer 适合查看纵向/横向

横向旋转后推送方向变化

在 iOS 7 上以横向模式处理 UIActivityViewController 后视图边界发生变化