状态栏和导航栏显示在iOS 7中我视图的边界上方


435

我最近下载了Xcode 5 DP来在iOS 7中测试我的应用程序。我注意到并确认的第一件事是,视图的边界并不一定总是调整为适应状态栏和导航栏的大小。

在中viewDidLayoutSubviews,我打印视图的边界:

{{0,0},{320,568}}

这导致我的内容出现在导航栏和状态栏下方。

我知道我可以通过获取主屏幕的高度,减去状态栏的高度和导航栏的高度来自己计算高度,但这似乎是不必要的额外工作。

如何解决此问题?

更新:

我已经找到了针对此特定问题的解决方案。将导航栏的半透明属性设置为NO:

self.navigationController.navigationBar.translucent = NO;

这样可以防止视图被框在导航栏和状态栏的下面。

但是,当您希望导航栏为半透明时,我还没有找到针对这种情况的解决方案。例如,以全屏方式查看照片时,我希望导航栏是半透明的,并且视图应位于其下方。那行得通,但是当我切换显示/隐藏导航栏时,我什至遇到了奇怪的结果。第一次更改子视图(UIScrollView)的边界。


我在xcode 5 DP中也遇到了同样的问题
Gopesh Gupta

让我知道您是否能找到解决方案
Gopesh Gupta

1
在导航栏中查找色调颜色属性,您应该能够将蓝色更改为所需的颜色。
beebcon

9
有时我讨厌ios升级,因为Apple从未给您机会让您的应用程序向后兼容。
Bagusflyer 2013年

3
如果问题与隐藏导航控制器顶部栏后状态栏下的视图有关,我将参考@Stunner stackoverflow.com/a/18976660/235206作为答案
MiKL 2013年

Answers:


495

您可以通过实现edgesForExtendedLayoutiOS7 SDK中的新属性来实现。请添加以下代码以实现此目的,

if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
        self.edgesForExtendedLayout = UIRectEdgeNone;

您需要在-(void)viewDidLoad方法中添加以上内容。

iOS 7对布局和自定义UI外观的方式进行了一些更改。视图控制器布局,色调颜色和字体的更改会影响应用程序中的所有UIKit对象。此外,手势识别器API的增强功能使您可以更精细地控制手势交互。

使用视图控制器

在iOS 7中,视图控制器使用全屏布局。同时,iOS 7使您可以更精细地控制视图控制器对视图进行布局的方式。特别是,全屏布局的概念已得到改进,以使视图控制器可以指定其视图的每个边缘的布局。

wantsFullScreenLayout视图控制器属性在iOS的7弃用如果您目前指定wantsFullScreenLayout = NO,当它在iOS的7运行视图控制器可显示其在一个意想不到的画面位置的内容。

要调整视图控制器对视图的布局方式,请UIViewController 提供以下属性:

  • edgeForExtendedLayout

edgesForExtendedLayout属性使用UIRectEdge类型,该类型除了指定无和全部外,还指定矩形的四个边缘中的每一个。使用edgesForExtendedLayout来指定一个视图的边缘应该扩展,而不管杆半透明的。默认情况下,此属性的值为UIRectEdgeAll

  • extendedLayoutIncludesOpaqueBars

如果您的设计使用不透明的条,edgesForExtendedLayout请将extendedLayoutIncludesOpaqueBars属性也设置为 NO进行优化。(的默认值extendedLayoutIncludesOpaqueBarsNO。)

  • 自动调整ScrollViewInsets

如果您不想自动调整滚动视图的内容插图,请设置automaticallyAdjustsScrollViewInsetsNO。(的默认值automaticallyAdjustsScrollViewInsetsYES)。

  • topLayoutGuide,bottomLayoutGuide

topLayoutGuidebottomLayoutGuide特性指示的顶部或底部边缘条的视图中的控制器的视图中的位置。如果条形图应与视图的顶部或底部重叠,则可以使用Interface Builder通过topLayoutGuide在bottomLayoutGuide 的底部或顶部创建约束来相对于条形图放置视图。(如果没有条形图应与视图重叠,则的底部 topLayoutGuide与视图的顶部bottomLayoutGuide相同,并且的顶部 与视图的底部相同。)当请求时,这两个属性都是延迟创建的。

请参考,苹果文档


2
它不会在iOS6下编译。我认为应该将其写为performselector ...
Shmidt

8
是的,这就是为什么我将选择器检查包含在if条件中,如果([self responsesToSelector:@selector(edgesForExtendedLayout)])
Nandha 2013年

19
如果没有导航栏,则无法使用。在这种情况下,我的看法是扩展了状态栏后面..
范·杜陈德良

4
我有与@VanDuTran相同的问题。如果隐藏了导航栏,则edgeForExtendedLayout没有帮助。
fishinear 2013年

6
它起作用了,但是……不再有半透明的效果了……我们如何也能保持半透明的效果呢?
Dipu Rajak 2013年

110

您无需计算将所有内容向下移动的距离,这有一个内置属性。在Interface Builder中,突出显示视图控制器,然后导航到属性检查器。在这里,您会在“扩展边缘”一词旁边看到一些复选框。如您所见,在第一个屏幕截图中,默认选择是将内容显示在顶部和底部栏的下方,而不是不透明栏的下方,这就是将栏样式设置为不透明的原因。

如您在第一个屏幕截图中所看到的,导航栏下方隐藏了两个UI元素。(我已经在IB中启用了线框来说明这一点),这些元素(一个UIButton和一个UISegmentedControl都将其“ y”原点设置为零,并且将视图控制器设置为允许顶部栏下方的内容)。

在此处输入图片说明

第二张屏幕截图显示了取消选中“顶部栏下方”复选框时发生的情况。如您所见,视图控制器视图已适当下移,以使其y原点位于导航栏的正下方。

在此处输入图片说明

也可以通过使用来以编程方式完成-[UIViewController edgesForExtendedLayout]。这是edgeForExtendedLayoutUIRectEdge的类引用的链接。

[self setEdgesForExtendedLayout:UIRectEdgeNone];

15
对于.xib中的视图,我该怎么做?
bobics

2
我在视图上添加了一个标签,并且按照您的指示进行了操作,但这对我
不起作用

5
@bobics对XIB问题的答案是“你不能。” 无论如何不通过IB。提起雷达,并希望苹果最终解决它。
回忆录,

感谢@ 0x7fffffff,这只是我想要的信息,非常有帮助。
Campo 2014年

33

我以编程方式创建了视图,最终为我工作:

- (void) viewDidLayoutSubviews {
    // only works for iOS 7+
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;

        // snaps the view under the status bar (iOS 6 style)
        viewBounds.origin.y = topBarOffset * -1;

        // shrink the bounds of your view to compensate for the offset
        viewBounds.size.height = viewBounds.size.height + (topBarOffset * -1);
        self.view.bounds = viewBounds;
    }
}

源代码(在第39页底部的topLayoutGuide部分中)。


终于找到了一个实际可行的答案。干得好!
StuartM 2013年

1
为了解决隐藏导航栏时视图控制器视图显示在状态栏下的问题,这是将视图捕捉到状态栏下的代码。
MiKL 2013年

注意:这会将视图的底部移出屏幕。
2013年

1
另外,除非您针对iOS7 进行构建,否则以上代码将引发错误- topLayoutGuide仅适用于iOS7。
回忆录,

1
还要注意,当主视图是UITableView时,每次滚动时都会调用viewDidLayoutSubviews。您的UITableView将按比例缩小,直到其高度为15px。添加一个标志以仅运行该代码一次。;)
Thomas Johannesmeyer

30

Swift 3 / Swift 4解决方案也可用于iOS 10+中的NIB / XIB文件:

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}

这就是帮助我的事情……如此简单。谢谢:-)
Hernan Arber

谢谢您,确实对我们有帮助
穆罕默德·艾哈迈德·拜格

这是10.x Swift 3+ IMO的最佳解决方案
shokaveli

10

如果您希望视图具有半透明的导航栏(这很不错),则必须设置一个contentInset或类似的内容。

这是我的方法:

// Check if we are running on ios7
if([[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."][0] intValue] >= 7) {
      CGRect statusBarViewRect = [[UIApplication sharedApplication] statusBarFrame];
      float heightPadding = statusBarViewRect.size.height+self.navigationController.navigationBar.frame.size.height;

      myContentView.contentInset = UIEdgeInsetsMake(heightPadding, 0.0, 0.0, 0.0);
}

3
您为什么不能直接将其与7.0相比较
Leena

1
大声笑我明白了:检查添加了次要功能的特定版本的功能较差。但是您正在检查该值是否更大或等于7.0,那么在这里就可以了;)
EeKay 2013年

1
@leena-这是7.x和更高版本中的功能-因此,我检查版本是否为7或更高,并跳过检查中的次要修订。
Magnus

2
我的TabView后面显示的tableView beeing出现问题。这使得表格的最后一行永远不会滚动到Tabbar上方。我像这样修复它:myTableView.contentInset = UIEdgeInsetsMake(0,0.0,TabbarHeight,0)
James Laurenstin 2013年

contentInset是的属性UIScrollView。如果我的主视图不是一个子类UIScrollView。那我该如何解决重叠问题呢?
2013年

9

edgesForExtendedLayout可以解决iOS 7的问题。但是,如果您跨iOS 7 SDK构建应用程序并将其部署在iOS 6中,则导航栏显示为半透明,视图位于其下方。因此,要针对iOS 7和iOS 6进行修复,请执行以下操作:

self.navigationController.navigationBar.barStyle = UIBarStyleBlackOpaque;
if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
    self.edgesForExtendedLayout = UIRectEdgeNone;   // iOS 7 specific

9

在您的应用程序plist文件中添加一行,将其称为“基于视图控制器的状态栏外观”并将其设置为NO


7

最简单的技巧是打开NIB文件并执行以下两个简单步骤:

  1. 只需将其切换并设置为您喜欢的一种即可:

在此处输入图片说明

  1. 选择要向下移动的UIView / UIIMageView /...。就我而言,只有徽标重叠了。我已将增量设置为+15;(如果在步骤1中选择了iOS 7,则为-15,或者)

在此处输入图片说明

结果

之前 后


6
它可以工作,但是看起来很难维护。最好只是解决问题而不是对其进行修补。
NLemay

最好以编程方式针对所有视图的子视图执行此操作,因为如果将其应用于主视图则不起作用
wildmonkey

5

快速解决方案:

override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated)
    self.edgesForExtendedLayout = UIRectEdge.None
}

4
现在这是edgesForExtendedLayout = []
Leon

1
由于这是一个公开的答案,我们不应该忘记致电:super.viewWillAppear(animated)
prodos

4

我想扩展一下Stunner的答案,并添加一条if语句来检查它是否为iOS-7,因为当我在iOS 6上对其进行测试时,我的应用程序将崩溃。

增加的内容将是:

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)

因此,我建议将此方法添加到您的MyViewControler.m文件中:

- (void) viewDidLayoutSubviews {
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        CGRect viewBounds = self.view.bounds;
        CGFloat topBarOffset = self.topLayoutGuide.length;
        viewBounds.origin.y = topBarOffset * -1;
        self.view.bounds = viewBounds;
    }
}

4

迅捷3

override func viewWillAppear(_ animated: Bool) {
    self.edgesForExtendedLayout = []
}

3

我有一种情况,我使用Apple编写的BannerViewController来显示广告,并使用BannerViewController中嵌入的ScrollViewController。

为了防止导航栏隐藏我的内容,我必须进行两项更改。

1)修改BannerViewController.m

- (void)viewDidLoad
{
   [super viewDidLoad];
   float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
   if (systemVersion >= 7.0) {
      self.edgesForExtendedLayout = UIRectEdgeNone;
   }
}

2)修改我的ScrollViewContoller

- (void)viewDidLoad
{
    [super viewDidLoad];
    float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
    if (systemVersion >= 7.0) {
        self.edgesForExtendedLayout = UIRectEdgeBottom;
    }
}

现在,广告可以正确显示在视图的底部,而不会被导航栏覆盖,并且顶部的内容不会被截断。




2

Swift 4.2-Xcode 10.0-iOS 12.0:

if #available(iOS 11.0, *) {} else {
  self.edgesForExtendedLayout = []
  self.navigationController?.view.backgroundColor = .white
}


1

从下拉列表中添加一行“基于View Controller的状态栏外观”键info.plist。像这样:

在此处输入图片说明


funny.it对我的cocos2d项目有帮助。当我切换此选项时,我可以看到顶部状态栏完全消失或出现。
Kursat Turkay 2013年

1

我在iPad上的应用程序(armv7,armv7s,amr64)遇到了相同的问题,只是出现了另一个UIViewController,然后在状态栏下将它们移到了导航栏后,我花了很多时间来找到相应的解决方案。我正在使用情节提要,并在UIViewController的InterfaceBuilder中使用,这很糟糕,我从FullScreen-> Current Context设置Presentation并解决了此问题。它仅在我的应用程序中适用于iPad => iOS8.0(使用iOS8.1进行测试)并且不适用于使用iOS 7.1的iPad!看截图


就我而言,我的主要观点是重叠我的tabBar,我不知道为什么。事实证明,“延伸边缘”>“底部栏下方”已选中。真的很难注意到它,因为我的应用程序的背景是白色的,并且只在我的tabBar上产生了一定程度的不透明度。谢谢!
耶稣罗德里格斯

0

在iOS 7中隐藏状态栏的步骤:

1.转到您的应用程序info.plist文件。

2.AndSet,基于视图控制器的状态栏外观:布尔型

希望我解决了状态栏问题.....


0

以我为例,loadView()中断了
此代码:self.edgesForExtendedLayout = UIRectEdgeNone

但是删除loadView()后一切正常

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.