ios 11 custom navbar goes under status bar
just downloaded xcode 9 and i'm having this weird issue, on ios 11 my custom navbar appears to be half in size and is under the status bar, on ios 10 works fine.
so here is my code
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)
here is a screenshot, ios11 on the left and ios10 on the right,
Solution 1:
Your code was always wrong. You should not be setting the height of a manually added navigation bar yourself or placing it at the top of the view. You should pin the top of the navigation bar to the bottom of the status bar (e.g. the top of the Safe Area) and give it a delegate so that you can use the UIBarPositioningDelegate mechanism to set its position to .topAttached
, which will cause it to stretch up to the top of the screen correctly.
(But you should also be asking yourself why you are adding a navigation bar manually. There is usually no reason not to wrap your view controller in a UINavigationController — even if you don't intend to do any actual navigation — just to get the navigation bar, with all its automatic management.)
Solution 2:
See ios 11 custom navbar goes under status bar / ios 11 navigation bar overlap status bar for an answer
Not sure if this is the same issue, but we ran into this as well when upgrading to iOS 11.
See ios 11 custom navbar goes under status bar
We were manually setting nav bar height to 64 and pinning to the superview edges. Conforming to the UINavigationBarDelegate protocol and implementing the UIBarPositioningDelegate delegate method solved it for us.
We replaced
navigationBar.autoPinEdgesToSuperviewEdgesExcludingEdge(.bottom)
navigationBar.autoSetDimension(.height, toSize: 64)
with
...
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
}
This is using the purelayout DSL for some of the autolayout calls (https://github.com/PureLayout/PureLayout)
Credit goes to https://stackoverflow.com/users/341994/matt for an answer
Solution 3:
Try adding some Auto Layout constraints after you add the nav bar to the view
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
}
You can actually use all but the third constraint in earlier versions of iOS but if it all works in earlier versions you may not want to mess with it.
Using the safe layout area should keep your nav bar under the status bar.
Solution 4:
First of all, make sure that your navigation controller's "shows navigation bar" is unchecked in storyboard.
Then, drag and drop navigation bar from the "object library". Give Top constraint equal to 20.
It'll also work perfect in "iPhone X simulator".
Happy Coding!
Solution 5:
Tried this solution in 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)
}