4

In my iOS 9+ app I use UINavigationBar in some of the UIViewControllers "manually" (= placing them directly in the VC instead of using UINavigationViewController).

Setting a height for such a UINavigationBar using a simple contraint was no problem before. However in iOS 11 the bar itself still correctly uses the assigned size, but the content is not positioned correctly any more (is now alligned to the top).

enter image description here

Any idea how to solve this?

EDIT:

I am pretty sure, that this is not a duplicate of "customizing iOS 11 navigation bar height customizing", this this question addresses a problem with UINavigationBar subclasses while I directly use UINavigationBar. Additionally the described problem seems to solved since Beta 4, while I am experiencing the problem in Beta 6.

EDIT 2:

Meanwhile I implemented a UINavigationBar subclass as proposed by CharlieSu in the other thread. However this did not solve the problem in my case. It seems that the subview frame are all set properly (without doing this manually), but the layout is broken anyway. So setting the frames manually does not make any difference.

Andrei Herford
  • 17,570
  • 19
  • 91
  • 225
  • Dont change the bar height, just use custom view on top of it or hide the bar, ios lower than 11 seems to have that issue – Tj3n Aug 16 '17 at 11:31
  • This would be a solution, however it would be pretty cumbersome if the `UINavigationBar` uses some kind of gradient background. Do you see the issue on the side of iOS 10 or below? I would say, that iOS 10- work as expected and that the iOS 11 layout is broken. – Andrei Herford Aug 16 '17 at 12:56
  • 4
    Possible duplicate of [iOS 11 navigation bar height customizing](https://stackoverflow.com/questions/44387285/ios-11-navigation-bar-height-customizing) – beyowulf Aug 16 '17 at 13:22
  • Here is my solution : https://stackoverflow.com/questions/46325181/ios-11-unable-to-change-navigation-bar-height – Shawn Baek Oct 05 '17 at 18:01

3 Answers3

2

I'm facing this problem right now. At first, It appears to be another height constraint in the bar that conflicts with mine, but mine has 1000 priority so it seems not to be the problem. Then I see another view inside UINavigationBar "UINavigationBarContentView", this view has height bigger than 0.

I then tried to set navigationBar.clipsToBounds = true and it works, cause parent view has the correct height...

EDIT: If you need to show the shadow of the bar, you will need clipToBounds = false. In that case you can subclass the NavigationBar

import UIKit

class SecondNavigationBar: UINavigationBar {
    override func layoutSubviews() {
        super.layoutSubviews()

        for subview in self.subviews {
            var stringFromClass = NSStringFromClass(subview.classForCoder)
            print("--------- \(stringFromClass)")
            if stringFromClass.contains("BarBackground") {
                subview.frame = self.bounds
            } else if stringFromClass.contains("UINavigationBarContentView") {
                subview.frame = self.bounds
            }
        }
    }
}
Eva Madrazo
  • 4,731
  • 2
  • 23
  • 33
2

I've had this problem, too. I solved it this way:

 -(void)layoutSubviews{
        [super layoutSubviews];
        CGRect rectStatus = [[UIApplication sharedApplication] statusBarFrame];
        if (rectStatus.size.height==44.f) {

        }else{
            if (@available(iOS 11.0, *)) {
                for ( UIView*aView in self.subviews) {
                    if ([NSStringFromClass(aView.classForCoder) isEqualToString:@"_UINavigationBarContentView"]) {
                        aView.frame = CGRectMake( 0,20,aView.frame.size.width,44);
                    }
                    else if ([NSStringFromClass(aView.classForCoder) isEqualToString:@"_UIBarBackground"]) {
                        aView.frame = CGRectMake(0,0,aView.frame.size.width, 64);
                    }
                }
            }
        }
    }
  • 2
    I am sorry I had to downvote this. I strongly believe this is an extremely dangerous and unstable hack that could get you rejected or worse, break the layout of your app completely at any time or with any iOS update – Ondrej Rafaj Jun 05 '18 at 20:15
0

In iOS 11, we can directly override barPosition in subclass of UINavigationBar (return UIBarPositionTopAttached instead default value UIBarPositionTop ) when u use custom UINavigationBar in UIViewController
like this :

- (UIBarPosition)barPosition {
    return UIBarPositionTopAttached;
}

the layout code will be like this:

    NSLayoutConstraint* a = [navigationBar.widthAnchor constraintEqualToAnchor:viewController.view.widthAnchor];
    NSLayoutConstraint *b = [navigationBar.centerXAnchor constraintEqualToAnchor:viewController.view.centerXAnchor constant:0];
    NSLayoutConstraint* c = [navigationBar.centerYAnchor constraintEqualToAnchor:viewController.view.topAnchor constant:X];

   [NSLayoutConstraint activateConstraints:@[a,b,c]];   

Don't set it's height ,it should always be 44.

It's works well in iOS 11. The view hierarchy is as same as UINavigationController's.
But it doesn't work below iOS 11. We need set the UINavigationBarDelegate to return UIBarPositionTopAttached in

- (UIBarPosition)positionForBar:(id <UIBarPositioning>)bar;  
  • 4
    you explained a lot of things except how to change the height of a uinavigationbar. :( – Duck Jan 30 '18 at 12:35