23
votes

I have a side menu that slides out to display a table view and from there I have segues that use the reveal view controller. The segue has to connect directly to the view controller; I can't use a navigation controller.

How do I add a navigation bar with a bar button item without a navigation controller?

the story board has the navigation item

the app does not

4

4 Answers

23
votes

While there are several smart ways to answer your question. I just solved it programmatically and wrote the following code in my viewWillAppear (note - viewDidLoad is also okay, but not suggested) -

-(void) viewWillAppear:(BOOL)animated {

    UINavigationBar *myNav = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
    [UINavigationBar appearance].barTintColor = [UIColor lightGrayColor];
    [self.view addSubview:myNav];


    UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc] initWithTitle:@"Cancel"
                                                                   style:UIBarButtonItemStyleBordered
                                                                  target:self
                                                                  action:nil];

    UIBarButtonItem *doneItem = [[UIBarButtonItem alloc] initWithTitle:@"Done"
                                                                 style:UIBarButtonItemStyleBordered
                                                                target:self action:nil];


    UINavigationItem *navigItem = [[UINavigationItem alloc] initWithTitle:@"Navigation Title"];
    navigItem.rightBarButtonItem = doneItem;
    navigItem.leftBarButtonItem = cancelItem;
    myNav.items = [NSArray arrayWithObjects: navigItem,nil];

    [UIBarButtonItem appearance].tintColor = [UIColor blueColor];
}

So, you have a white navigation bar with blue bar button items without a Navigation controller. Again, there are other ways to implement it in your case. Hope, this was helpful.

Output -

enter image description here

Update -

To add images -

UIImageView *myImage = [[UIImageView alloc] initWithFrame:CGRectMake(0,10,32,32)];
[myImage setImage:[UIImage imageNamed:@"image.png"]];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:myImage];
[self.view addSubview:myImage];
7
votes

Swift 4 Version

 let navigationBar = UINavigationBar(frame: CGRect(x: 0, y: 0, width: 320, height: 50))
    navigationBar.barTintColor = UIColor.lightGray
    view.addSubview(navigationBar)

    let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: nil)
    let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: nil)

    let navigationItem = UINavigationItem(title: "Title")
    navigationItem.leftBarButtonItem = cancelButton
    navigationItem.rightBarButtonItem = doneButton

    navigationBar.items = [navigationItem]
6
votes

There is a way to use the NavigationItem in interface builder for this.

First add a NavigationItem to your ViewController in the interface builder, like you would with a NavigationController. Make sure to make the NavigationBar is visible by selecting something other than Inferred and None under simulated metrics.

Second, in viewDidLoad, just add the following lines:

- (void)viewDidLoad 
{
    [super viewDidLoad];

    UINavigationBar *bar = [[UINavigationBar alloc] initWithFrame: frame];
    bar.items = @[self.navigationItem];
    [self.view addSubview: bar];
}

As for frame, width will be the same as your ViewController and height will be either 44.0 or 64.0 depending if the status bar is visible or not.

CGFloat navigationBarHeight = 44.f + [UIApplication sharedApplication].statusBarFrame.size.height;
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, navigationBarHeight);

And if you wish to support different orientations use NSLayoutConstraints:

    CGFloat navigationBarHeight = 44.f + [UIApplication sharedApplication].statusBarFrame.size.height;
[self.view addConstraints: @[
    [NSLayoutConstraint constraintWithItem: self.view
                                 attribute: NSLayoutAttributeLeft
                                 relatedBy: NSLayoutRelationEqual
                                    toItem: bar
                                 attribute: NSLayoutAttributeLeft
                                multiplier: 1.0
                                  constant: 0.0],
    [NSLayoutConstraint constraintWithItem: self.view
                                 attribute: NSLayoutAttributeRight
                                 relatedBy: NSLayoutRelationEqual
                                    toItem: bar
                                 attribute: NSLayoutAttributeRight
                                multiplier: 1.0
                                  constant: 0.0],
    [NSLayoutConstraint constraintWithItem: self.view
                                 attribute: NSLayoutAttributeTop
                                 relatedBy: NSLayoutRelationEqual
                                    toItem: bar
                                 attribute: NSLayoutAttributeTop
                                multiplier: 1.0
                                  constant: 0.0],
    [NSLayoutConstraint constraintWithItem: bar
                                 attribute: NSLayoutAttributeHeight
                                 relatedBy: NSLayoutRelationEqual
                                    toItem: nil
                                 attribute: NSLayoutAttributeNotAnAttribute
                                multiplier: 1.0
                                  constant: navigationBarHeight],
                             ]];
1
votes

be very careful about adding in "viewWillAppear", as this method can be called more times, (for example is a modal appears....) so use a lazy approach:

1) declare a var:

var myNav: UINavigationBar?

2) test if already set:

viewWillAppear:(BOOL)animated {
if self.myNav != nil{
     return
}
self.myNav = ....

3) be sure remove exiting controller, for example on didDisappear...

note.. is not correct to specify size.. if iOS rotates, it does not work fine..