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

时间:2013-06-12 20:06:41

标签: ios ios7

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

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

  

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

这会导致我的内容显示在导航栏和状态栏下方。

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

如何解决此问题?

更新

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

self.navigationController.navigationBar.translucent = NO;

这将修复视图在导航栏和状态栏下面的框架。

但是,当您希望导航栏为半透明时,我还没有找到修复此案例的方法。例如,在全屏查看照片时,我希望导航栏是半透明的,并且要在其下方构建视图。这是有效的,但当我切换显示/隐藏导航栏时,我经历了甚至更奇怪的结果。第一个子视图(UIScrollView)每次都会更改其边界的原点。

19 个答案:

答案 0 :(得分:494)

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

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   提供以下属性:

     
      
  • edgesForExtendedLayout
  •   
     

edgesForExtendedLayout属性使用UIRectEdge类型,   除了之外,它还指定了每个矩形的四条边   指定none和all。使用edgesForExtendedLayout指定哪个   无论条形半透明,都应该扩展视图的边缘。通过   默认情况下,此属性的值为UIRectEdgeAll

     
      
  • extendedLayoutIncludesOpaqueBars
  •   
     

如果您的设计使用不透明条形,请改进edgesForExtendedLayout   还将extendedLayoutIncludesOpaqueBars属性设置为   即可。 (默认值extendedLayoutIncludesOpaqueBars。)

     
      
  • automaticallyAdjustsScrollViewInsets
  •   
     

如果您不希望滚动视图的内容插入是自动的   调整后,将automaticallyAdjustsScrollViewInsets设置为。 (该   默认值automaticallyAdjustsScrollViewInsets。)

     
      
  • topLayoutGuide,bottomLayoutGuide
  •   
     

topLayoutGuidebottomLayoutGuide属性表示   视图控制器视图中顶部或底部条边的位置。   如果条形图应与视图的顶部或底部重叠,则可以使用   Interface Builder通过创建来相对于栏定位视图   限制在topLayoutGuide的底部或顶部   bottomLayoutGuide。 (如果没有条形图与视图重叠,则底部应该重叠   topLayoutGuide与视图顶部和顶部相同   bottomLayoutGuide与视图的底部相同。)两者   属性是在请求时延迟创建的。

请参阅apple doc

答案 1 :(得分:110)

你不必计算将所有东西都降下来的距离,这里有一个属性。在Interface Builder中,突出显示视图控制器,然后导航到属性检查器。在这里,您会看到“Extend Edges”字样旁边的复选框。正如您所看到的,在第一个屏幕截图中,默认选择是内容显示在顶部和底部条形下,而不是在不透明条形下,这就是为什么将条形样式设置为不半透明的原因。

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

enter image description here

第二个屏幕截图显示取消选中“Under Top Bars”复选框后会发生什么。如您所见,视图控制器视图已正确向下移动,其y原点位于导航栏下方。

enter image description here

这也可以通过-[UIViewController edgesForExtendedLayout]的使用以编程方式完成。以下是edgeForExtendedLayoutUIRectEdge

的类引用的链接
[self setEdgesForExtendedLayout:UIRectEdgeNone];

答案 2 :(得分: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;
    }
}

Source(位于第39页底部的 topLayoutGuide 部分)。

答案 3 :(得分:25)

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

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}

答案 4 :(得分: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);
}

答案 5 :(得分:9)

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

答案 6 :(得分: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

答案 7 :(得分:7)

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

  1. 只需切换并将其设置为您喜欢的那个:
  2. Enter image description here

    1. 选择要移动的UIView / UIIMageView / ...在我的情况下,只有徽标重叠,我已将delta设置为+15; (如果您在步骤1中选择了iOS 7,则为OR -15)
    2. Enter image description here

      结果

      Before After

答案 8 :(得分:5)

Swift Solution:

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

答案 9 :(得分:4)

Swift 3

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

答案 10 :(得分: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;
    }
}

答案 11 :(得分: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;
    }
}

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

答案 12 :(得分:2)

只需在视图中设置以下代码即可。

  if ([[[UIDevice currentDevice] systemVersion] floatValue]<= 7) {
self.edgesForExtendedLayout = UIRectEdgeNone;
 }

答案 13 :(得分:1)

对我来说,最简单的解决方案是在plist中添加两个键

enter image description here

答案 14 :(得分:1)

我的应用程序通过iPad(armv7,armv7s,amr64)与我的应用程序有同样的问题,只有通过呈现另一个UIViewController并且在解除它们后,状态栏下的导航栏... 我花了很多时间为此找到任何解决方案。我正在使用故事板和在InterfaceBuilder中使用UIViewController,这让我很糟糕,我从FullScreen设置了Presentation - &gt;当前的上下文,它解决了这个问题。它适用于我的应用程序仅适用于iPad =&gt; iOS8.0(使用iOS8.1测试)和适用于iOS 7.1的iPad无法正常工作!! see screenshot

答案 15 :(得分:1)

从下拉列表中添加“基于视图控制器的状态栏外观”键,作为info.plist中的一行。这样的事情:

Enter image description here

答案 16 :(得分:0)

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

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

2.And Set,查看基于控制器的状态栏外观:布尔值NO

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

答案 17 :(得分:0)

在我的情况下,loadView()中断了 这段代码: self.edgesForExtendedLayout = UIRectEdgeNone

但删除loadView()后一切正常

答案 18 :(得分:0)

Swift 4.2-Xcode 10.0-iOS 12.0:

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