iOS7 - 状态栏下的视图 - edgesForExtendedLayout无法正常工作

时间:2013-09-24 19:21:05

标签: iphone ios objective-c xcode ios7

我有一个去年建成的项目,它使用的是XIB,没有故事板。 XIB不使用自动布局,但它们确实使用了一些自动调整大小。运行iOS7时出现问题,其中所有视图都隐藏在状态栏下。我完全理解这是iOS7的新功能,可以预期这一点。但是,所有用于修复它的解决方案都不起作用。我在视图顶部有一个图像,它总是显示在状态栏下面,我没有使用导航栏或类似的东西。

我尝试更新XIB中的Y-delta(它们对视图没有影响),我尝试将edgesForExtendedLayout设置为UIRectEdgeNone(什么都不做),以及其他众多的东西。每次状态栏都显示隐藏在它下面的视图,无论我做什么......除非我手动向下移动XIB中的视图以留出状态栏的空间(但该解决方案不起作用,因为它当然,在iOS6中看起来并不正确。

奇怪的是,即使我尝试使用一行代码来破解视图移位,它也不起作用(如下所示):

self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y+20, self.view.frame.size.width, self.view.frame.size.height);

..并不是说我会选择这种解决方案,但奇怪的是它不起作用(我通常看到不工作的唯一一次是如果自动布局到位,这不是在这种情况下)。

这是状态栏显示的设计要求,我只是难以理解为什么我无法将视图设置为iOS7的状态栏。我已阅读有关该主题的每个Stack Overflow帖子,以及Apple的过渡/指南。再一次,重申一下,我完全理解它应该如何运作以及预期的解决方案应该是什么,但这些似乎都不适用于这个特定的项目。

我是一个经验丰富的iOS开发人员,但这个项目是由另一个团队构建的,所以我不知道是否有某些东西隐藏在XIB文件,plist或代码中,可能胜过上述设置。请告诉我是否有其他可以查看的内容,或者我可以提供的更多信息。

提前致谢!

7 个答案:

答案 0 :(得分:17)

如果在Interface Builder中设置iOS 6/7 delta值,请记住在Interface Builder Document上将“View as”设置为“iOS 6”,因为它是您要复制的iOS 6布局。然后,仅在iOS 7上使用增量将内容推送到状态栏下方。如果您将“查看为”设置为iOS 7(默认设置),则增量将在iOS 6上为您提供iOS 7外观。

但是,如果您根据视图框架以编程方式重新定位或调整视图大小,则增量将无法帮助您,因为框架不考虑增量。

我找到的最佳解决方案是在主XIB上启用自动布局,然后在顶部/内容视图上设置顶部空间约束,以遵循顶部布局指南,而不是使用增量。本指南在iOS 7中引入,代表状态栏下方的位置。遗憾的是,当不使用Storyboard时,Interface Builder中没有该指南,但您可以通过编程方式添加它。

我所做的是在界面生成器中向superview添加顶级空间约束,并在代码中为此创建了一个插座。然后,在viewDidLoad中,如果topLayoutGuide可用(iOS 7+),请使用Top Layout Guide替换此插座中的约束。

if ([self respondsToSelector:@selector(topLayoutGuide)]) {
    [self.view removeConstraint:self.containerTopSpaceConstraint];

    self.containerTopSpaceConstraint =
    [NSLayoutConstraint constraintWithItem:self.contentView
                                 attribute:NSLayoutAttributeTop
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:self.topLayoutGuide
                                 attribute:NSLayoutAttributeBottom
                                multiplier:1
                                  constant:0];

    [self.view addConstraint:self.containerTopSpaceConstraint];

    [self.view setNeedsUpdateConstraints];
    [self.view layoutIfNeeded];
}

答案 1 :(得分:6)

作为参考,当我将它应用于我的ViewControllers时,下面的解决方案确实有效。然而,它并不理想,而且有点hacky。如果这是我能采取的唯一方法,那么就这样吧。

float systemVersion=[[[UIDevice currentDevice] systemVersion] floatValue];
if(systemVersion>=7.0f)
{
    CGRect tempRect;
    for(UIView *sub in [[self view] subviews])
    {
        tempRect = [sub frame];
        tempRect.origin.y += 20.0f; //Height of status bar
        [sub setFrame:tempRect];
    }
}

答案 2 :(得分:5)

Apple正在推动您使用autolayout来实现这一目标。您需要在视图的顶部子视图中为“顶部布局指南”设置约束。

请参阅此文档以获取示例:

https://developer.apple.com/library/ios/qa/qa1797/_index.html

要在没有XIB的情况下执行此操作,您需要以编程方式添加约束。 Apple的文档给出了一个很好的例子,我在下面总结了这一点。

认为topLayoutGuide是视图控制器上的属性,只需在变量绑定字典中使用它即可。然后像普通一样设置约束:

id topGuide = [myViewController topLayoutGuide];
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(button, topGuide);
NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide]-20-[button]" options:0 metrics:nil views:viewsDictionary]; 

可以找到in the UIViewController class reference的文档。

答案 3 :(得分:3)

1)如果您不介意使用不透明的导航栏,那么这是最简单的解决方案:

self.navigationController.navigationBar.translucent = NO;

2)svguerin3的答案在一般情况下不起作用。例如,如果您的某个子视图使用自动调整大小挂钩到其容器的底部,则其新位置将是错误的。在最坏的情况下,它可能会离开屏幕。

答案 4 :(得分:2)

- (void)viewDidAppear:(BOOL)animated {
        [self.view setFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height)];
// OR
        self.view.transform = CGAffineTransformMakeTranslation(0, 20);
}

答案 5 :(得分:0)

您是否尝试将XIB视为源并删除包含edgesforextendedlayout ??

的任何行

我们必须在故事板的场景中删除这一行,因为我们的故事板的场景主要视图由XIB代表

我们发生的事情是,不知何故,在某些场景中,场景主视图的XIB内容被状态栏和导航栏的高度向下推。

删除该行允许显示XIB,就好像它们的顶部始于其故事板场景的同一顶部。

可悲的是,我们不知道触发了这个是什么,但我发现在更改XIB主视图中内容的顺序时会发生这种情况,因此首先出现UITextView。触发此项后,重新排列项目的顺序对删除此不需要的行为没有任何影响。

希望这有助于其他任何人遇到此类问题。

答案 6 :(得分:0)

如果您正在使用故事板,则在设置视图的顶部布局后,您可以取消选中" Under Opaque Bars"在属性检查器

Storyboard