iOS 7状态栏与NavigationBar重叠问题

47

我在我的应用程序中有一个视图控制器,在storyboard中拖动了一个导航栏。它在iOS 6中工作得很好,但在iOS 7中看起来像这样:

ios 7 status bar nav var

状态栏和导航栏不应该重叠。我在stackoverflow上看到了很多这样的问题,但对我没有太大帮助。

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

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

更新: 我已将视图控制器嵌入uinavigation控制器中。删除了手动添加的导航栏。现在在storyboard中看起来还好,但运行时会显示如下内容:

iOS 7 Navigation Status bar

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


我已经在这个帖子上回答了https://dev59.com/fGMl5IYBdhLWcg3wknsT#19044681 - Desert Rose
您的应用程序下方没有显示任何内容吗? - Desert Rose
在状态栏下方有一个导航栏,下方是一个文本视图。但现在导航栏区域是透明的,并显示其后面的另一个视图控制器已经呈现了它。 - AJ112
我花了一天时间尝试 SO 和苹果开发者论坛提出的各种解决方案 - 嵌入导航控制器并使用它的导航栏是唯一看起来还算像样的方法。我提交了一个 RADAR,鼓励其他遇到这个问题的人也这么做。 - RyanR
2017年,完整详细的解决方案:https://dev59.com/j2Ik5IYBdhLWcg3wrv24#41622164 - Fattie
17个回答

65

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

现在,状态栏是透明的,而位于其后面的导航栏则透过它显示。导航栏图像甚至可以延伸到状态栏后面。

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

现在来回答你的问题。首先我能看到两个不同的问题。一个是你的状态栏和导航栏都有点相互冲突,就像你在问题中展示的图片所示。

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

解决第一个问题的方法:你可以使用UIBarPositionTopAttached,或者你可以使用视图边界和帧。我也可以向你建议和链接到Apple的文档等等,但这需要一些时间来解决问题。

解决此问题最好且最简单的方法是将您的视图控制器嵌入导航控制器中,就像这样:只需选择视图控制器,然后转到Editor > Embed In > Navigation Controller。 (如果您的旧导航栏中有任何内容,您可以先将其拖动下来,在嵌入视图控制器之前,将视图控制器嵌入导航控制器,然后将栏按钮移动到新导航栏上,最后删除旧导航栏)

第二个问题的解决方案: 这个解决方案是针对您在更新中提到的具体问题,而不是为了让大众阅读。您可以看到导航栏和状态栏不可见,透明区域显示父视图控制器。我不确定您面临这个问题的原因,但最有可能是与 ECSlidingView 或其他第三方库有关。您可以在Storyboard中选择此视图控制器,并将视图的背景颜色设置为与导航栏相同。这将停止在后面显示父视图控制器,您的导航栏和状态栏将开始显示。现在您可以用文本视图或任何其他想要使用的方式覆盖其余的视图控制器。

希望这可以帮助到您!


2
只需将您的视图控制器嵌入导航控制器中即可。这行代码让我在 uitabbarcontroller 中与带提示的栏苦苦挣扎了两天。现在问题终于解决了,但还有一个问题:现在栏的一部分不透明,透明部分仅在状态栏下方。您能提供原因吗? - trickster77777
找到了问题 - 它设置了背景颜色。它必须是透明的。 - trickster77777
1
如果您的应用程序不是在整个应用程序中都使用导航控制器(就像我一样),那么最好的方法就是将问题视图控制器嵌入导航控制器中。我向您致敬,因为您明确指出了这一点。我已经为此问题挣扎了很长时间(在开发之间来回摆弄),最后决定嵌入控制器,并且它的工作效果非常好!其他解决方案并没有按预期工作(可能是因为我使用ECSlidingView作为初始根控制器)。 - Roy Jacobs
将视图控制器嵌入外壳导航控制器,非常巧妙。+1 - Jeremy
不要费心使用下面的“捷径”方法。根据你的iOS版本和/或视图控制器,它们可能有效,也可能无效。我尝试了所有这些方法,以查看它们是否适用于TableView控制器,但一个都没有成功。按照KC所说的做就可以了。 - Snickers

33

由于 iOS 7 开始,状态栏更像是整个视图控制器的覆盖层,因此导航栏过于靠近状态栏。由于您的导航栏位于 (0, 0) 处,状态栏将显示在导航栏的顶部。要解决这个问题,只需将导航栏下移(或者按照其他人所说),在导航栏和 topLayoutGuide 之间创建一个约束。

这样做后,您会发现导航栏和屏幕顶部之间现在有一个 20 点的间隙。那是因为您刚刚将导航栏向下移动了 20 点。"但 UINavigationController 可以做到啊!" 当然可以,并且它通过在您的视图控制器上实现 UIBarPositioningDelegate 来实现。这是一个包含一个方法的协议,应该像这样实现:

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

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

另一个您正在看到的是导航栏是半透明的,这意味着导航栏下面的任何东西都可以在一定程度上可见。在iOS 7上,UINavigationBartranslucent属性默认设置为YES。在iOS 7之前,默认值为NO


更好的方法是将您的UINavigationBar的“高度”设置为64,而不是44。然后,您的栏将像Apple的应用程序一样延伸到顶部。 - Aaron Brager
1
@AaronBrager:我的解决方案也是做同样的事情。将高度改为64有什么优点? - Scott Berrevoets
按照广告所述运作,别忘了将实现positionForBar:方法的类设置为导航栏的代理。这是一个有点烦人的hack,但它确实有效 :) - zeraien
@zeraien:这真的不是黑客行为。它是设计成这样完成的。我认为设计可能会更好一些,但这就是应该完成的方式,也可能是UINavigationController的完成方式。 - Scott Berrevoets
1
+1 这对我来说完美地运作。正如zeraien所说,确保为导航栏设置了委托。 - jpecoraro342
显示剩余5条评论

4
您可以简单地执行以下操作:
1)在导航栏和顶部布局指南之间添加约束(选择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
}

3

2

使用Swift:

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

public protocol UINavigationBarDelegate : UIBarPositioningDelegate {
   ...
}

您只需要设置使用Storyboard设置的UINavigationBardelegate并实现该方法即可,就像这样:

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 如果某个解决方案不能解决您的问题,但对其他人有效,我认为这不是投反对票的理由。 - Victor Sigler

2

首先,在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;

迄今为止最好的解决方案! - Fattie
对于2017年,这是使用Swift剪切和粘贴的相同解决方案!带有完整的细节。希望能帮助到某些人!https://dev59.com/j2Ik5IYBdhLWcg3wrv24#41622164 - Fattie

2
这对我有效,希望你也有同样的运气 :).
在您的视图中添加以下代码。
-(void) viewDidLayoutSubviews
{
    CGRect tmpFram = self.navigationController.navigationBar.frame;
    tmpFram.origin.y += 20;
    self.navigationController.navigationBar.frame = tmpFram;
}

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


2

如果有人还需要帮助,以下是我在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;
}

它对我也起作用,但不知道这是否是正确的方法,可能会在项目后期出现一些问题。 - iPhone 7

2
如果您的UIViewController不在UINavigationController中,并且您正在使用UIStoryBoard,则可以将“iOS 6/7 Delta”设置为20,用于需要从UIStatusBar偏移的每个子视图的delta Y。

enter image description here


2

这是IOS7的新功能。与其盯着20像素的导航栏,不如盯着0像素。解决方案是将整个视图向下移动到20像素,或者可以使用高度为64像素的导航栏图像。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接