Programmatically change height of navigation bar in swift

14,913

Solution 1

update for iOS 11 and beyond

apple doesn't want you messing with the navigation bar height, so don't touch it see here: https://openradar.appspot.com/32912789 and here: https://forums.developer.apple.com/thread/88202#274620

class TallerNaviBar: UINavigationBar {
    override func sizeThatFits(size: CGSize) -> CGSize {
        var newSize:CGSize = CGSizeMake(self.superview!.frame.size.width, 87)
        return newSize
    }
}

I don't do swift, but the answer is easy, here's ObjC

- (CGSize)sizeThatFits:(CGSize)size {

         return CGSizeMake([self superview].frame.size.width, 40);

}

Here's my interpretation in Swift:

import UIKit
class TallerNaviBar: UINavigationBar {
    override func sizeThatFits(size: CGSize) -> CGSize {
        var newSize:CGSize = CGSizeMake(superview.width, 87)
        return newSize
    }
}

The problem you will have isn't with this method, this is the easy part, the problem is forcing the navigation controller to always use this navigation bar

I subclass and resize everything in IOS, including navigation controllers and tabbarcontrollers, in order to enforce that all navigation controllers use this navigation bar, you must subclass a navigationController and only use this navigationcontroller throughout your app, here's how the subclass works, this is Obj C, so you'll have to translate it:

@interface NSHNavigationController () <UINavigationBarDelegate, UINavigationControllerDelegate>
{

}

@implementation NSHNavigationController

#pragma mark Initialization

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self NSHSetupNavigationController];
    }
    return self;
}

- (instancetype)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass
{
    self = [super initWithNavigationBarClass:navigationBarClass toolbarClass:toolbarClass];
    if (self) {
        [self NSHSetupNavigationController];
    }
    return self;
}

- (id)initWithRootViewController:(UIViewController *)rootViewController
{
    self = [super initWithRootViewController:rootViewController];
    if (self) {
        [self NSHSetupNavigationController];
    }
    return self;
}

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        [self NSHSetupNavigationController];
    }
    return self;
}

- (void)dealloc
{
    [self setInternalDelegate:nil];
    [self setExternalDelegate:nil];
}

#pragma mark Setup

- (void)NSHSetupNavigationController
{
    [self setValue:[[NSHNavigationBar alloc]init] forKeyPath:@"navigationBar"];
}

this is the line that will do it for you:

   [self setValue:[[NSHNavigationBar alloc]init] forKeyPath:@"navigationBar"];

Oh yeah, and make sure you are subclassing the nav bar, you said you were, but here's how you do it, it's simple:

#import "NSHNavigationBar.h"

@implementation NSHNavigationBar
- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        NSDictionary *attributes = @{NSForegroundColorAttributeName:[UIColor whiteColor],
                                     NSFontAttributeName:fontMagicForRegularNSHFont};
        [self setTitleTextAttributes:attributes];
        [self setTranslucent:true];
        [self setBackgroundColor:[UIColor clearColor]];
    }
    return self;
}
- (CGSize)sizeThatFits:(CGSize)size {

    return CGSizeMake([self superview].frame.size.width, heightResizer(40));

}

- (void)layoutSubviews {

    [super layoutSubviews];

}

So, in summary, subclass both the UINavigationBar and the UINavigationController and you are set, this will allow you to manipulate the navigation bar whenever you'd like, you can also type cast your view controller's navigation bars, this is a little nuts and will confuse a lot of people, but here it goes:

-(CustomNavigationBar *)navBar {

    return (id)[self.navigationController navigationBar];
}

put the stuff above in your view controller and then you call it like this:

[[self navBar] setBackGroundColor:[UIColor blueColor]];

This will successfully typecast your navigationcontroller to be your custom navigation bar, if you want to change the height of the nav bar from here, then you can do something like this:

Solution 2

Here is a simple Swift 3 solution based on minimal subclassing. First subclass UINavigationBar.:

class CustomNavigationBar: UINavigationBar {
    override func sizeThatFits(_ size: CGSize) -> CGSize {
        let newSize :CGSize = CGSize(width: self.frame.size.width, height: 54)
        return newSize
    }
}

Create the navigation controller in code and use the initializer that takes your custom navigation bar class.

let nav = UINavigationController(navigationBarClass: CustomNavigationBar.self, 
                                 toolbarClass: nil)

All existing behavior for UINavigationBar is preserved and your custom height is adopted.

Share:
14,913
Aiden
Author by

Aiden

Updated on June 05, 2022

Comments

  • Aiden
    Aiden almost 2 years

    I want to make a taller navigation bar and I am trying to do this using a subclass of UINavigationBar.

    Here is my subclass of UINavigationBar:

    import UIKit
    class TallerNaviBar: UINavigationBar {
        override func sizeThatFits(size: CGSize) -> CGSize {
            var newSize:CGSize = CGSizeMake(size.width, 87)
            return newSize
        }
    }
    

    And in my ViewController which is embedded in a navigation controller, I write the following code in the viewDidLoad() function

    self.navigationController!.setValue(TallerNaviBar(frame: CGRectMake(0, 0, self.view.frame.size.width, 87)), forKeyPath: "navigationBar")
    

    There is no error reported, but I get nothing when I run the code. A completely blank view. enter image description here.

    Any suggestion? Or some other way of changing the height? Thanks.

  • Hemang
    Hemang over 6 years
    How to set custom navigation bar class inside UIStoryboard? I tried changing the class name but it doesn't work.
  • crypt
    crypt almost 6 years
    Not working on iOS 11. I created subclass of UINavigationController and UINavigationBar as described above. In storyboard, changed the class names of UINavigationController and UINavigationBar to the respective subclass names. But height is not changing.
  • NiBE
    NiBE almost 6 years
    sizeThatFits is not support anymore in ios11
  • Larry Pickles
    Larry Pickles about 5 years
    @Vakas it's no longer supported see here: forums.developer.apple.com/thread/88202#274620 and here: openradar.appspot.com/32912789 apple doesn't want you messing with the navigation bar height, so i'd leave it alone, tell your client to F off
  • seyha
    seyha about 3 years
    how to set rootViewController?