iOS 7 状态栏与 NavigationBar 冲突

Posted

技术标签:

【中文标题】iOS 7 状态栏与 NavigationBar 冲突【英文标题】:iOS 7 Status Bar Collides With NavigationBar 【发布时间】:2013-10-06 23:56:54 【问题描述】:

我的应用中有一个视图控制器,它在故事板中拖了一个导航栏。它在 ios 6 中运行良好,但在 iOS 7 中看起来像这样:

状态栏和导航栏不应相互碰撞。我在堆栈溢出上看到了很多这样的问题,但它们对我没有太大帮助。

有些问题说我应该使用这个“self.edgesForExtendedLayout = UIRectEdgeNone;”但它没有用。有人说我应该删除导航栏并将其嵌入导航控制器中,由于我的程序实现方式,我无法做到这一点。一些解决方案建议使用视图边界,但它对我也不起作用。

可以帮助我解决此问题的一件事是什么。提前致谢!

更新:我已将视图控制器嵌入到 uinavigation 控制器中。删除了之前手动添加的导航栏。现在它在情节提要中看起来不错,但是当我运行它时,它显示以下内容:

它正在显示当前位于它后面的另一个视图控制器的文本,它是它的父视图控制器。意味着它现在是透明的。谁能指出我做错了什么?

【问题讨论】:

我已经在这个帖子上回答了***.com/questions/18294872/… @DesertRose 请检查我的更新 你是不是在状态栏下面没有显示任何内容? 状态栏下方有一个导航栏,下方有一个文本视图。但是现在导航栏区域是透明的,并且显示了它背后的另一个视图控制器。 我花了一天时间尝试 SO 和苹果开发者论坛上建议的所有解决方案 - 嵌入导航控制器并使用它的导航栏是唯一看起来不错的东西。我提交了 RADAR,并鼓励其他有此问题的人也这样做。 【参考方案1】:

最新版本的 iOS 带来了许多视觉上的变化,从开发者的角度来看,导航和状态栏是两个明显的变化。

状态栏现在是透明的,它后面的导航栏可以显示出来。导航栏图像甚至可以延伸到状态栏后面。

首先,如果你是一个初学者并且刚刚开始iOS开发并且对状态栏和导航栏的工作方式感到困惑,你可以简单地阅读我发现非常有用的博客文章HERE。它拥有 iOS 7 中与导航和状态栏相关的所有信息。

现在来回答你的问题。首先,我可以看到两个不同的问题。一个是您的状态栏和导航栏都相互碰撞,如您在带有图像的问题中所示。

问题:问题是您之前在视图控制器中拖动了一个导航栏,该导航栏在 iOS 6 中正常工作,但随着 iOS 7 SDK 的到来,这种方法会导致状态栏和导航栏相互重叠。

第一个问题的解决方案:您可以使用 UIBarPositionTopAttached 或者您可以使用视图边界和框架,我也可以建议并将您链接到 Apple's documentation 和 bla bla bla 但这需要一些时间为您解决问题。

解决此问题的最佳和最简单的方法就是将您的视图控制器嵌入导航控制器中,仅此而已。您只需选择视图控制器并转到编辑器 > 嵌入 > 导航控制器 即可。 (如果你的旧导航栏有内容,可以先往下拉,将视图控制器嵌入到导航控制器中,然后移动新导航栏上的栏按钮,然后删除旧导航栏)

第二个问题的解决方案:此解决方案适用于您在更新中提到的特定问题,不适用于阅读本文的公众。如您所见,导航和状态栏不可见,透明区域显示父视图控制器。我并没有真正使用你为什么面临这个问题,但很可能是因为涉及到一些第三方库,如 ECSlidingView 或任何其他库。您可以在情节提要中选择此视图控制器,并将视图的背景颜色设置为与导航栏相同。这将停止在后面显示父视图控制器,并且您的导航栏和状态栏将开始显示。现在您可以使用文本视图或您在其中使用的任何内容来覆盖视图控制器的其余部分。

希望这会有所帮助!

【讨论】:

> 只是将您的视图控制器嵌入到导航控制器中,这条线花费了我 2 天的时间与 uitabbarcontroller 中的提示条进行斗争。现在问题终于解决了,但是有一个问题:现在部分栏不透明,透明部分只在状态栏下。你能提出原因吗? 发现了问题——设置了背景颜色。它必须是透明的。 如果你没有在整个应用程序中使用导航控制器(比如我),最好的办法就是将问题视图控制器嵌入到导航控制器中。我向你明确指出这一点表示敬意。我一直在摆弄这个问题很长一段时间(在开发过程中和开发之间),最终解决了它并嵌入了控制器,它就像一个魅力!其他解决方案没有按预期工作(可能是因为我使用 ECSlidingView 作为初始根控制器)。 在 shell 导航控制器中嵌入视图控制器,聪明。 +1 不要为下面那些骇人听闻的“捷径”方法而烦恼。根据您的 iOS 版本和/或视图控制器,它们可能工作也可能不工作。我尝试了所有这些以查看它们是否可以与 TableView 控制器一起使用,而没有一个可以。照 KC 说的做。【参考方案2】:

导航栏离状态栏太近了,因为从 iOS 7 开始,状态栏更多的是覆盖在整个视图控制器的视图上。由于您的导航栏位于 (0, 0),因此状态栏将显示在导航栏的顶部。要解决这个问题,只需将导航栏向下移动(或者,正如其他人所说),在导航栏和 topLayoutGuide 之间创建一个约束。

当你这样做时,你会看到导航栏和屏幕顶部之间现在有 20 磅的差距。那是因为您刚刚将导航栏向下移动了 20 点。 “但是UINavigationController可以做到!”当然,它通过在您的视图控制器上实现UIBarPositioningDelegate 来实现。这是一个单方法协议,应该像这样实现:

- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar 
    return UIBarPositionTopAttached;

将视图控制器添加为导航栏的代理后,您会注意到导航栏仍向下移动了 20 个点,但其背景会在状态栏下方向上延伸,就像在 UINavigationController 中一样。

您看到的另一件事是导航栏是半透明的,这意味着导航栏下方的任何内容都会在某种程度上可见。 UINavigationBar 上的 translucent 属性在 iOS 7 上默认设置为 YES。在 iOS 7 之前,默认设置为 NO

【讨论】:

一个更好的方法是让你的 UINavigationBar 的height 等于 64 而不是 44。然后你的栏会一直延伸到顶部,就像在 Apple 的应用程序中一样。 @AaronBrager:我的解决方案做同样的事情。是什么让将高度更改为 64 是更好的解决方案? @Snickers:对我和其他一些人有用。你可能做错了什么。 完美!这使得半透明/模糊与状态栏很好地一起消失。谢谢 +1 这对我来说非常有效。正如 zeraien 所说,请确保为导航栏设置委托。【参考方案3】:

你可以这样做:

1) 在Navigation BarTop Layout Guide之间添加一个约束(选择navigationBar,按住ctrl键进入Bottom Layout Guide,松开ctrl键)

2) 选择垂直间距

3) 设置常量为0

结果:

更新

在您的 AppDelegate 文件中,您可以添加以下内容:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool 

  // Prevent Navigationbar to cover the view
  UINavigationBar.appearance().translucent = false

【讨论】:

【参考方案4】:

我建议你在你的 viewDidLoad 方法中尝试一下:

self.navigationController.navigationBar.translucent = NO;

(现在默认是yes)

https://developer.apple.com/library/ios/documentation/uikit/reference/UINavigationBar_Class/Reference/UINavigationBar.html#//apple_ref/occ/instp/UINavigationBar/translucent

【讨论】:

【参考方案5】:

这对我有用,我希望你也有同样的运气:)。 在您的视图中添加以下代码。

-(void) viewDidLayoutSubviews

    CGRect tmpFram = self.navigationController.navigationBar.frame;
    tmpFram.origin.y += 20;
    self.navigationController.navigationBar.frame = tmpFram;

它基本上改变了导航栏的位置。

【讨论】:

【参考方案6】:

这是 IOS7 的新功能。而不是在 IOS7 中盯着 20 px 的导航栏盯着 0 px。作为一种解决方案,将整个视图向下移动到 20 像素,或者您可以将图像用于高度为 64 像素的导航栏。

【讨论】:

【参考方案7】:

如果它仍然对某人有帮助,这对我在 ios 7 及更高版本中将导航栏向下移动一点有用:

-(void)viewWillLayoutSubviews

    float iosVersion = 7.0;
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= iosVersion) 
        // iOS 7+
        CGRect viewFrame = self.view.frame;
        viewFrame.origin.y += 10;
        self.view.frame = viewFrame;
    

在 ios 6.1 及以下的设备上,导航栏将保持不变。

这就是我用来使状态栏的内容变亮的方法:

-(UIStatusBarStyle)preferredStatusBarStyle
    return UIStatusBarStyleLightContent;

【讨论】:

它也适用于mw,但不知道这是不是正确的方法,它可能会给以后的项目带来一些麻烦。【参考方案8】:

如果您的UIViewController 不在UINavigationController 中并且您使用的是UIStoryBoard,您可以将增量 Y 的“iOS 6/7 Deltas”设置为 20,对于每个需要偏移的子视图来自UIStatusBar

【讨论】:

【参考方案9】:

使用 Swift

正如@Scott Berrevoets 在他的回答中所说,您需要在协议UIBarPositioningDelegate 中实现方法positionForBar,但由于UINavigationBarDelegate 协议实现了此协议:

public protocol UINavigationBarDelegate : UIBarPositioningDelegate 
   ...

你只需要设置你使用Storyboard设置的UINavigationBar中的delegate并实现方法就完成了,就像这样:

class ViewController: UIViewController, UINavigationBarDelegate 

   @IBOutlet weak var navigationBar: UINavigationBar!

   override func viewDidLoad() 
       super.viewDidLoad()
       self.navigationBar.delegate = self 
   

   override func didReceiveMemoryWarning() 
       super.didReceiveMemoryWarning()
       // Dispose of any resources that can be recreated.
   

   func positionForBar(bar: UIBarPositioning) -> UIBarPosition 
       return UIBarPosition.TopAttached
   

注意: 值得一提的是,如果你设置导航栏的y轴的位置,比如说从顶部到40,那么它会从这个位置向下延伸到顶部,以模拟行为UINavigationController 的个数,您需要从顶部设置为 20。

希望对你有帮助。

【讨论】:

@AndreyKonstantinov 如果某些解决方案不能解决您的问题,而对于某些人来说,我认为这不是投反对票的理由。【参考方案10】:

首先,在 Info.plist 中将UIViewControllerBasedStatusBarAppearance 设置为 NO。 然后,在AppDelegateapplication:didFinishLaunchingWithOptions:方法中添加:

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) 
   [application setStatusBarStyle:UIStatusBarStyleLightContent];
   self.window.clipsToBounds = YES;
   self.window.frame = CGRectMake(0, 20, self.window.frame.size.width, self.window.frame.size.height-20);
   self.window.bounds = CGRectMake(0, 20, self.window.frame.size.width, self.window.frame.size.height);
 
 return YES;

【讨论】:

迄今为止最好的解决方案! 对于 2017 年,这是使用 Swift 进行剪切和粘贴的相同解决方案!有完整的细节。希望它可以帮助某人! ***.com/a/41622164/294884【参考方案11】:

在 iOS 7 应用程序占用 100% 的屏幕大小。这不是问题。 http://www.doubleencore.com/2013/09/developers-guide-to-the-ios-7-status-bar/

【讨论】:

【参考方案12】:

在早期的 iO​​S 窗口中,在状态栏之后开始,在 iOS 7 中,窗口从 0px 开始,在早期版本中,视图高度为 460(iPhone 4s 及更早版本)和 548(iPhone 5),但在 iOS 7 中,视图高度为 480(iPhone 4s 及更早版本) 和 568(iPhone 5 及更高版本),因此您必须在 2o px 之后开始视图排列,或者您必须从 20px 开始视图。

您可以在 rootviewcontroller 或所有 viewcontroller 中编写以下代码以设置 20px 的视图

#define IOS7_HEIGHT             64

- (void)viewDidLayoutSubviews 
    NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    if ([currSysVer compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending)
    
        CGRect frame=[self.view frame];
        if (frame.origin.y!=IOS7_HEIGHT) 

            frame.origin.y = IOS7_HEIGHT;
            frame.size.height -= IOS7_HEIGHT;
            [self.view setFrame:frame];
            [self.view layoutSubviews];
        
    

这里的高度是 64,因为状态栏是 20,导航栏是 44。 试试下面的代码,它会帮助你。你的问题就会得到解决。

【讨论】:

【参考方案13】:

对于那些在实现@Masterfego 的解决方案时遇到问题的人(这也是官方的,但我在 Xcode 6.3 和自动约束方面遇到了问题),这就是我所做的:

我有一个带有导航栏的 UIViewController。我选择了导航栏并添加了 64 像素的高度约束。我们稍后会看到导航栏会更高的警告(但这就是我们所做的)。最后,您可以看到状态栏看起来不错,并且与导航栏颜色相同。 :)

PS:我还不能发布图片。

【讨论】:

【参考方案14】:

您可能可以创建附加到顶部布局指南的约束,以指定导航栏相对于状态栏的位置。有关使用布局指南的更多信息,请参阅iOS 7 UI Transition Guide: Appearance and Behavior section。

【讨论】:

过渡指南提供了更多详细信息。你能用我能做些什么来解决这个问题来更新你的答案吗?谢谢!【参考方案15】:

这是最好的答案。 但我想知道如何使用Storyboard 并将UINavigationBar 拖到上面。 当我实现委托方法,并将返回结果设置为UIBarPositionTopAttached时,它不起作用。

- (void)viewDidLoad
    self.navigationbar.delegate = self;

- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar
    NSLog(@"Got it");
    //
    //    CGRect frame = self.navigaitonBar.frame;
    //
    //    frame = CGRectMake(0, 20, CGRectGetWidth(frame), CGRectGetHeight(frame));
    //    self.navigaitonBar.frame = frame;
    //
    //    NSLog(@"frame %f",frame.origin.y);
    return UIBarPositionTopAttached;

【讨论】:

只想使用 - (UIBarPosition)positionForBar:(id)bar;在下方状态栏更改导航栏位置。【参考方案16】:

如果你使用 Xcode 6 和 Swift,你可以做到:

    打开应用的 info.plist 文件。 如果 ViewControllerBasedStatusBarAppearance 布尔键不存在,则添加该键并赋值“NO”。 如果“状态栏样式”键不存在,则添加它并为其选择“不透明黑色样式”值。

【讨论】:

【参考方案17】:

当全屏ModalViewController 从我的MainViewController 打开时我遇到了问题,当用户从ModalViewController 返回到MainViewControllerNavigationBar 的位置发生了变化。

我注意到的问题是,当用户返回MainViewController 时,没有包含状态栏高度。请在回到您的ViewController 之前和之后调试并检查您的NavigationBar 的来源。

// This method will adjust navigation bar and view content.
    private func adjustNavigationControllerIfNeeded() 

        var frame = self.view.frame
        let navigationBarHeight = self.navigationController!.navigationBar.frame.size.height

        if(frame.origin.y == navigationBarHeight && !UIApplication.shared.isStatusBarHidden)  

   // If status bar height is not included but it is showing then we have to adjust 
      our Navigation controller properly

            print("Adjusting navigation controller")
            let statusBarHeight = UIApplication.shared.statusBarFrame.height

            frame.origin.y += statusBarHeight // Start view below navigation bar
            frame.size.height -= statusBarHeight
            self.view.frame = frame

            self.navigationController!.navigationBar.frame.origin.y = statusBarHeight // Move navigation bar
        
    

并从 viewWillAppear 方法中调用它 -

override func viewWillAppear(_ animated: Bool) 

        super.viewWillAppear(animated)
        self.adjustNavigationControllerIfNeeded()

【讨论】:

以上是关于iOS 7 状态栏与 NavigationBar 冲突的主要内容,如果未能解决你的问题,请参考以下文章

iOS 7 状态栏与 UIImagePickerController 上的相机控件重叠

在 iOS 7 中让导航栏与状态栏重叠

IBM Worklight - iOS 7 状态栏与应用程序的 HTML 重叠

如何在 iOS 7 中使用 NavigationBar 背景图像 44px 高度更改状态栏背景?

iOS11中如何设置导航栏与ViewController内容重叠

关于状态栏与导航栏的设置及自定义