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

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

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

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

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

我该如何解决这个问题?

更新:

我已经找到了解决这个问题的方法。将导航栏的半透明属性设置为NO:

self.navigationController.navigationBar.translucent = NO;

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

然而,我还没有找到一个修复的情况下,当你想导航栏是半透明的。例如,在全屏查看一张照片时,我希望导航栏是半透明的,视图被框在它下面。这是可行的,但是当我切换显示/隐藏导航栏时,我经历了更奇怪的结果。第一个子视图(一个UIScrollView)每次都会改变它的边界y原点。


如果你想让视图有半透明的导航栏(这很好),你必须设置一个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);
}

你可以通过在iOS7 SDK中实现一个名为edgesForExtendedLayout的新属性来实现这一点。请添加以下代码来实现此功能,

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

你需要在你的-(void)viewDidLoad方法中添加上面的内容。

iOS 7 brings several changes to how you layout and customize the appearance of your UI. The changes in view-controller layout, tint color, and font affect all the UIKit objects in your app. In addition, enhancements to gesture recognizer APIs give you finer grained control over gesture interactions. Using View Controllers In iOS 7, view controllers use full-screen layout. At the same time, iOS 7 gives you more granular control over the way a view controller lays out its views. In particular, the concept of full-screen layout has been refined to let a view controller specify the layout of each edge of its view. The wantsFullScreenLayout view controller property is deprecated in iOS 7. If you currently specify wantsFullScreenLayout = NO, the view controller may display its content at an unexpected screen location when it runs in iOS 7. To adjust how a view controller lays out its views, UIViewController provides the following properties: edgesForExtendedLayout The edgesForExtendedLayout property uses the UIRectEdge type, which specifies each of a rectangle’s four edges, in addition to specifying none and all. Use edgesForExtendedLayout to specify which edges of a view should be extended, regardless of bar translucency. By default, the value of this property is UIRectEdgeAll. extendedLayoutIncludesOpaqueBars If your design uses opaque bars, refine edgesForExtendedLayout by also setting the extendedLayoutIncludesOpaqueBars property to NO. (The default value of extendedLayoutIncludesOpaqueBars is NO.) automaticallyAdjustsScrollViewInsets If you don’t want a scroll view’s content insets to be automatically adjusted, set automaticallyAdjustsScrollViewInsets to NO. (The default value of automaticallyAdjustsScrollViewInsets is YES.) topLayoutGuide, bottomLayoutGuide The topLayoutGuide and bottomLayoutGuide properties indicate the location of the top or bottom bar edges in a view controller’s view. If bars should overlap the top or bottom of a view, you can use Interface Builder to position the view relative to the bar by creating constraints to the bottom of topLayoutGuide or to the top of bottomLayoutGuide. (If no bars should overlap the view, the bottom of topLayoutGuide is the same as the top of the view and the top of bottomLayoutGuide is the same as the bottom of the view.) Both properties are lazily created when requested.

请参考,苹果医生


你不需要计算要往下平移多远,这有一个内置属性。在Interface Builder中,突出显示视图控制器,然后导航到属性检查器。在这里你会看到一些复选框旁边的文字“扩展边缘”。正如你所看到的,在第一个截图中,默认的选择是让内容出现在顶部和底部的栏下,而不是在不透明的栏下,这就是为什么将栏样式设置为不半透明的原因。

正如你在第一张截图中看到的,有两个UI元素隐藏在导航栏下面。这些元素,一个UIButton和一个UISegmentedControl都有他们的“y”原点设为零,视图控制器被设置为允许内容低于顶部栏。

这第二张截图显示了当你取消选择“顶部栏下”复选框时会发生什么。正如你所看到的,视图控制器视图已经适当地向下移动,因为它的y原点在导航栏的正下方。

这也可以通过使用-[UIViewController edgesForExtendedLayout]来实现。这里有一个edgeForExtendedLayout和UIRectEdge类引用的链接

[self setEdgesForExtendedLayout:UIRectEdgeNone];

在你的app plist文件中添加一行,命名为“View controller-based status bar appearance”,并将其设置为NO。


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

只需切换它并将其设置为您喜欢的一个:

选择那些UIView的/UIIMageView的/…你想要下移。在我的例子中,只有徽标重叠,我已经将delta设置为+15;(如果第一步选择iOS 7,则为-15)

结果是:


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

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


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

- (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部分)。


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

增加的内容是:

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

我建议把这个方法添加到你的myviewcontroller中。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;
    }
}

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


我有一个场景,我使用苹果编写的BannerViewController来显示我的广告和嵌入在BannerViewController中的ScrollViewController。

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

1)修改BannerViewController.m

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

2)修改我的scrollviewcontroller

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

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


隐藏状态栏的步骤:

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

2.和设置,查看基于控制器的状态栏外观:布尔NO

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


我在ipad (armv7, armv7s, amr64)上的应用程序也有同样的问题,只是通过呈现另一个UIViewController,并在驳回它们后,在状态栏下进入导航栏… 我花了很多时间来寻找解决方案。我使用故事板和在InterfaceBuilder的UIViewController,这使得糟糕的我设置从全屏->当前上下文的演示,它修复了这个问题。它在我的应用程序只适用于ipad => iOS8.0(测试与iOS8.1)和ipad与iOS 7.1不工作!!


只要在视图中设置以下代码就会出现。

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

迅速的解决方案:

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

像这样对顶部布局做一个约束


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

override func viewDidLoad() {
    super.viewDidLoad()

    edgesForExtendedLayout = []
}

在我的例子中,loadView()被中断 这段代码: 自我。edgesForExtendedLayout = UIRectEdgeNone

但删除loadView()后一切工作正常


斯威夫特3

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

Swift 4.2 - Xcode 10.0 - iOS 12.0:

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