Is there a way to change the height of a UINavigationBar in Storyboard without using a UINavigationController?

IosObjective CCocoa TouchUinavigationcontrollerUinavigationbar

Ios Problem Overview


I want to use a custom UINavigationBar in one of my views, which is not a part of any UINavigationController-hierarchy. When I drag a UINavigationBar into Storyboard, it shows like this:

UINavigationBar

This bar is 44px, which would be enough if the status bar wouldn't share this space. Because iOS7 lets us use the entire screen, including the space for the status bar, the UINavigationBar should be 64px tall, not 44px.

If I connect the view to a UINavigationController's hierarchy, then it shows correct:

UINavigationController

I read somewhere that if the UINavigationBar has the property barPosition: set to UIBarPositionTopAttached, then the bar would be 64px. This is, however, a readonly-property.

My search results have only shown something I consider a "work-around". By adding a useless UINavigationController before this UIViewController, I can pretend to have a hierarchy, and it will add the UINavigationBar with 64px automatically.

Is there really no way to have a 'rogue'(without the help of a navigation controller) UINavigationBar that covers 64px? If that is the case, is there any valid reasons as to why?

(I'm not saying the UINavigationBar should be 64px by default, but there should be an option for it in the inspector)

(I also see people answering with programmatic ways to solve this. Even though these answers works, I'd still have to design the storyboard with that in mind (a gap). What I want to know is if it's possible to set this in storyboard, or rather, why isn't it allowed?)

Ios Solutions


Solution 1 - Ios

You can set the property barPosition to UIBarPositionTopAttached another way!

  1. Add a delegate to your UINavigationBar.

  2. Implement -positionForBar: in the delegate class:

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

Your navigation bar's top must also be anchored to the Top Layout Guide.

Solution 2 - Ios

You can change the nav bar height programmatically:

[navBar setFrame:CGRectMake(0, 0, 320, 64)];

Edit: As I wrote in the comments, you may have to put this line in viewDidLayoutSubviews to circumvent autolayout.

Solution 3 - Ios

You can set it to attach to the top of the view using 'User Defined Runtime Attributes' in 'Identity Inspector' in Interface Builder. Set the barPosition property.

enter image description here

Here's the documentation for the barPosition property: https://developer.apple.com/library/ios/documentation/uikit/reference/UIBarPositioning_Protocol/Reference/Reference.html

Solution 4 - Ios

There is a way to accomplish this WITHOUT using a UINavigationController or setting it programmatically. Just set a height constraint on the navigation bar to whatever you want, 64 in this instance.

You can accomplish the same thing programmatically as such:

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:navigationBar attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeHeight multiplier:1 constant:64.0f]];

EDIT:

As @nerdist-colony pointed out, when working with Autolayout it's always been to set translatesAutoresizingMaskIntoConstraints to NO otherwise there may be conflicts in the constraints.

Solution 5 - Ios

I'm using a standalone UINavigationBar too and I encountered the same issue, and I found there is two ways fixing this properly.

I fixed it using constraints, and a parent UIView. I set this UIView in the storyboard as the parent view of my UINavigationBar with a {0, 0, 320, 64} frame. You can add a constraint or a set of constraints forcing the UINavigationBar to have the desired size. And given that your parent UIView has the correct frame in your storyboard, you can layout as usual your other views in your storyboard.

Now if autolayout is disabled you can change the bar height programmatically as described in Lindsey's answer. -(void)viewDidLayoutSubviews seems to be a good spot to do it.

Solution 6 - Ios

If you using Autolayout, you can set Height of UINavigationBar's constraint to 64 or event more.

Solution 7 - Ios

@startupThekid:

iOS will generate an exception if you try to change autoresizing mask for a UINavigationBar that is managed by a UINavigationController.

However, the Swift equivalent of the objective C code you posted is:

var navBar = self.navigationController!.navigationBar 

in viewDidAppear():

navBar.setTranslatesAutoresizingMaskIntoConstraints = false

Wherever you need to set the constraint:

var navBarHeightConstraint = 
      NSLayoutConstraint(item: navBar, attribute: .Height,
            relatedBy: .Equal, toItem: nil, 
            attribute: .Height, multiplier: 1, constant: height)

self.view.addConstraint(navBarHeightConstraint)

Therafter you should be able to modify the constant property of the constraint as necessary to alter the nav bar height, such as for change in device orientation

Solution 8 - Ios

I've written a blog post detailing how to do this with minimal code intervention. Your bar will show a gap in the storyboard, but it will work fine on the device. In short, the steps are:

  1. Add the navigation bar to the view controller in the storyboard.

  2. Set the constraints for the navigation bar in the storyboard:

    • Navigation Bar.Top = Top Layout Guide.Bottom
    • Navigation Bar.Leading = Superview.Leading
    • Navigation Bar.Trailing = Superview.Trailing
  3. Connect the storyboard's navigation bar to its view controller as an @IBOutlet.

  4. In the view controller's class, add a UINavigationBarDelegate protocol to the class declaration.

  5. In the view controller's viewDidLoad method, set the navigation bar's delegate to self.

  6. In the view controller, add the bar positioning delegate's positionForBar method. Return the UIBarPosition representing TopAttached. (Note: UINavigationBarDelegate inherits this method from UIBarPositioningDelegate.)

The full post with GIF images is here:
Easily use a Navigation Bar without a corresponding Navigation Controller

These steps work as of Swift 2.1/Xcode 7.2

Solution 9 - Ios

In Swift 3 using the main storyboard you can use constraints to change the height and make it work. This was the way that I found is easy to implement.

Creating the constraints.

What it looks like in the end.

Solution 10 - Ios

I was in the same boat and having problems, but now I've fixed it. I'm trying to do the right things to avoid setting the frame explicitly, which is desirable for future-proofing and easy support for different device sizes. In my case, I'm wanting a webview beneath a navigation bar.

I'm setting my view controller to be a UINavigationBarDelegate and implementing positionForBar: to return UIBarPositionTopAttached, like user3269713's answer. It seemed like the other trick was to use auto-layout to position the bar below the topLayoutGuide.

This was the code I was using in viewDidLoad after creating navigation bar & webview programmatically, and I was still seeing the bar stuck at height 44 but couldn't immediately see why:

    [navigationBar sizeToFit];
    navigationBar.delegate = self;
    [self.view addSubview:navigationBar];
    [self.view addSubview:webView];
    id guide = self.topLayoutGuide;
    NSDictionary *viewNamesDict = NSDictionaryOfVariableBindings(webView, navigationBar, guide);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[webView]|" options:0 metrics:nil views:viewNamesDict]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[guide][navigationBar][webView]|" options:0 metrics:nil views:viewNamesDict]];

But I did some more thinking and playing around with auto-layout, and it turns out it that alone was the cause of my problem. I was trying to rely on navigation bar's translated constraints from its autoresizing mask, but it turned out I needed to defined them explicitly. Here's my new viewDidLoad code that works:

    [navigationBar sizeToFit];
    navigationBar.delegate = self;
    navigationBar.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:navigationBar];
    [self.view addSubview:webView];
    id guide = self.topLayoutGuide;
    NSDictionary *viewNamesDict = NSDictionaryOfVariableBindings(webView, navigationBar, guide);
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[navigationBar]|" options:0 metrics:nil views:viewNamesDict]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[webView]|" options:0 metrics:nil views:viewNamesDict]];
    NSString *verticalLayoutVisualExpression = [NSString stringWithFormat:@"V:|[guide][navigationBar(%f)][webView]|", navigationBar.frame.size.height];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalLayoutVisualExpression options:0 metrics:nil views:viewNamesDict]];

And yes, as I'd hoped, this automatically moves the bar when turning to landscape and the status bar hides.

(I heartily recommend a auto-layout helper like Masonry which makes layout code more concise, and Masonry, for one, takes care of turning off translatesAutoresizingMaskIntoConstraints for you)

Solution 11 - Ios

I know this is a very hacky way of doing this, but for me it worked. I have a NavigationViewController and I want to load a ViewController modally which has a UINavigationBar at the top with Done and Cancel buttons. This is what it looked like:enter image description here

As you can see there is a white band at the top that I want to be the same color as the UINavigationBar. Instead of changing the height of the UINavigationBar programmatically, I just made a new view and set its background color equal to that of the UINavigationBar (HEX = F8F8F8, RGBA = 248,248,248,1.0). Again, I know this is super hacky, but it gets the job done for me. Here is what it looks like now

enter image description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStiView Question on Stackoverflow
Solution 1 - Iosuser3269713View Answer on Stackoverflow
Solution 2 - IosLyndsey ScottView Answer on Stackoverflow
Solution 3 - IosjoerickView Answer on Stackoverflow
Solution 4 - IosbarndogView Answer on Stackoverflow
Solution 5 - IoskketchView Answer on Stackoverflow
Solution 6 - IosmrcuongthView Answer on Stackoverflow
Solution 7 - IosclearlightView Answer on Stackoverflow
Solution 8 - IosleanneView Answer on Stackoverflow
Solution 9 - IosFreitDevView Answer on Stackoverflow
Solution 10 - IosPierre HoustonView Answer on Stackoverflow
Solution 11 - IossbruView Answer on Stackoverflow