iOS 11自定义导航栏被覆盖在状态栏下方

12

刚下载了Xcode 9,我遇到了这个奇怪的问题,在iOS 11上,我的自定义导航栏显示为一半大小,并且在状态栏下方,而在iOS 10上却可以正常工作。

这是我的代码:

let newNavbar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 64))
let navItem = UINavigationItem()

//create and assign the items

newNavbar.setItems([navItem], animated: false)
view.addSubview(newNavbar)

这里有一张屏幕截图,左边是iOS11,右边是iOS10。

输入图片说明


看起来这个问题相关:https://dev59.com/yKXja4cB1Zd3GeqPOUBd. - finneycanhelp
5个回答

28
您的代码一直有误。您不应该手动设置导航栏的高度或将其置于视图顶部。您应该将导航栏的顶部固定在状态栏底部(例如安全区域的顶部),并为其提供代理,以便使用UIBarPositioningDelegate机制将其位置设置为.topAttached,这将使其正确地延伸到屏幕顶部。
(但您也应该问问自己为什么要手动添加导航栏。通常没有理由不将您的视图控制器包装在UINavigationController中-即使您不打算进行任何实际的导航-只是为了获得带有所有自动管理的导航栏。)

1
那就试试我的建议吧。 - matt
2
您的顶部空间约束为零到父视图。这不是我要做的事情。实际上,这正是我说不要做的事情。 - matt
1
该死,你是对的,现在它正在工作,谢谢,我非常感激。 - iknowNothing
1
@NevinJethmalani 是的,你肯定是没问题的。没有什么能阻止模态segue到导航控制器。如果你需要帮助,请将其作为一个真正的问题提出,这样我就可以看到实际的问题。谢谢! - matt
1
{btsdaf} - matt
显示剩余11条评论

6
请参阅iOS 11自定义导航栏与状态栏重叠 / iOS 11导航栏覆盖状态栏以获得答案。
不确定是否同一问题,但是我们在升级到iOS 11时也遇到了此问题。
请参阅iOS 11自定义导航栏与状态栏重叠 我们手动将导航栏高度设置为64并将其固定在超级视图边缘。符合UINavigationBarDelegate协议并实现UIBarPositioningDelegate委托方法解决了我们的问题。
我们进行了如下替换:
navigationBar.autoPinEdgesToSuperviewEdgesExcludingEdge(.bottom)
navigationBar.autoSetDimension(.height, toSize: 64)

使用

...
  if #available(iOS 11.0, *) {
    navigationBar.topAnchor.constraint(
      equalTo: self.view.safeAreaLayoutGuide.topAnchor
    ).isActive = true
  } else {
    navigationBar.topAnchor.constraint(
      equalTo: topLayoutGuide.bottomAnchor
    ).isActive = true
  }
  navigationBar.autoPinEdge(toSuperviewEdge: .left)
  navigationBar.autoPinEdge(toSuperviewEdge: .right)
  navigationBar.delegate = self
...

public func position(for bar: UIBarPositioning) -> UIBarPosition
  return .topAttached
}

这里使用了PureLayout DSL来进行自动布局调用 (https://github.com/PureLayout/PureLayout)

感谢https://stackoverflow.com/users/341994/matt的回答。


3
在将导航栏添加到视图后,请尝试添加一些自动布局约束。
if #available(iOS 11.0, *) {
    newNavbar.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
    newNavbar.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    newNavbar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    newNavbar.heightAnchor.constraint(equalToConstant: 64).isActive = true
}

在早期版本的iOS中,您实际上可以使用除第三个约束条件之外的所有约束条件,但是如果所有内容都在早期版本中正常工作,则可能不想对其进行更改。

使用安全布局区域应该将您的导航栏保持在状态栏下方。


当我们尝试设置您提到的新约束时,出现了崩溃。 - dineshprasanna
@dineshprasanna - 你解决了这个崩溃问题吗?问题出在哪里?我也遇到了一个崩溃,显示“它们没有共同的祖先。约束或其锚点引用不同视图层次结构中的项目是非法的。” - Lohith Korupolu

1

在 Swift 4.1 中尝试了这个解决方案

let menuBar: UIView = {
let mb = UIView()
mb.backgroundColor = .red
mb.translatesAutoresizingMaskIntoConstraints = false
return mb
}()



private func setupMenuBar(){

view.addSubview(menuBar)

let constraints = [ menuBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                    menuBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                    menuBar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                    menuBar.heightAnchor.constraint(equalToConstant: 50)]
NSLayoutConstraint.activate(constraints)
}

1
首先,确保你在故事板中取消了导航控制器的“显示导航栏”选项。
然后,从“对象库”中拖放导航栏。将顶部约束设置为20。
它也适用于“iPhone X模拟器”。
编码愉快!

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