109

I have a view controller hierarchy and the top-most controller is displayed as a modal and would like to know how to display the navigation bar when using

'UIViewController:presentViewController:viewControllerToPresent:animated:completion'

The docs for 'presentViewController:animated:completion:' note:

'On iPhone and iPod touch, the presented view is always full screen. On iPad, the presentation depends on the value in the modalPresentationStyle property.'

For 'modalPresentationStyle', the docs say:

The presentation style determines how a modally presented view controller is displayed onscreen. On iPhone and iPod touch, modal view controllers are always presented full-screen, but on iPad there are several different presentation options.

Is there way to ensure that the navigation bar is visible below the status bar once the view control displays itself? Should I interpret the doc as, you don't get any options of iPhone/iPod and only on iPad?

Previously, I was using 'UIViewController:presentModalViewController:animated' which worked fine, but since iOS 5.0, the API has been deprecated so I'm switching over to the new one.

Visually, what I'm looking to do is have the new controller slide in from the bottom of the screen, just like the old API used to do.

[updating with code]:

// My root level view:
UIViewController *vc = [[RootViewController alloc] 
                            initWithNibName:nil 
                            bundle:[NSBundle mainBundle]];
navController = [[UINavigationController alloc] initWithRootViewController:vc];        
....

// Within the RootViewController, Second view controller is created and added 
// to the hierarchy. It is this view controller that is responsible for 
// displaying the DetailView:
SecondTierViewController *t2controller = [[SecondTierViewController alloc] 
                                           initWithNibName:nil
                                           bundle:[NSBundle mainBundle]];

[self.navigationController pushViewController:t2controller animated:YES];

// Created by SecondTierViewController 
DetailViewController *controller = [[DetailViewController alloc] initWithNibName:nil                                                                                 
                                        bundle:[NSBundle mainBundle]];  

controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
controller.modalPresentationStyle = UIModalPresentationCurrentContext;

[self.navigationController presentViewController:controller 
                                        animated:YES 
                                        completion:nil];
Raheel Sadiq
  • 9,847
  • 6
  • 42
  • 54
Jonas Gardner
  • 2,458
  • 5
  • 22
  • 28

12 Answers12

197

It is true that if you present a view controller modally on the iPhone, it will always be presented full screen no matter how you present it on the top view controller of a navigation controller or any other way around. But you can always show the navigation bar with the following workaround way:

Rather than presenting that view controller modally present a navigation controller modally with its root view controller set as the view controller you want:

MyViewController *myViewController = [[MyViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *navigationController = 
    [[UINavigationController alloc] initWithRootViewController:myViewController];

//now present this navigation controller modally 
[self presentViewController:navigationController
                   animated:YES
                   completion:^{

                        }];

You should see a navigation bar when your view is presented modally.

mfaani
  • 33,269
  • 19
  • 164
  • 293
Manish Ahuja
  • 4,509
  • 3
  • 28
  • 35
  • That is pretty much what I started with. But the reason I'm not using 'presentModalViewController' is because it is noted as a deprecated API. – Jonas Gardner Mar 15 '12 at 18:22
  • this is what has been written in the UIViewController class: // Display another view controller as a modal child. Uses a vertical sheet transition if animated.This method has been replaced by presentViewController:animated:completion: // It will be DEPRECATED, plan accordingly. - (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated; so simply call the new method and pass nil for completion and you should be good. – Manish Ahuja Mar 15 '12 at 18:24
  • Great answer. Updated to use `(void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^)(void))completion` – Wayne Jul 18 '14 at 15:00
  • 3
    When I attempt to present a navigation controller, it crashes (`'NSInvalidArgumentException', reason: 'Pushing a navigation controller is not supported'`). How can this work? – oarfish Aug 07 '15 at 10:31
  • In my case it shows bar but the other content is placed incorrectly on presenting animation. And only after this animation it jumps into the correct position. – Vyachaslav Gerchicov Nov 26 '15 at 13:13
  • @oarfish can you share the code so that I can help debug? – Manish Ahuja Dec 17 '15 at 07:59
  • @ManishAhuja Thanks, but I think i worked around this problem somehow, or let it go. I would have to dig around a lot to find out where it occurred. – oarfish Dec 17 '15 at 08:28
60

Swift 5.*

Navigation:

guard let myVC = self.storyboard?.instantiateViewController(withIdentifier: "MyViewController") else { return }
let navController = UINavigationController(rootViewController: myVC)

self.navigationController?.present(navController, animated: true, completion: nil)

Going Back:

self.dismiss(animated: true, completion: nil)

Swift 2.0

Navigation:

let myVC = self.storyboard?.instantiateViewControllerWithIdentifier("MyViewController");
let navController = UINavigationController(rootViewController: myVC!)

self.navigationController?.presentViewController(navController, animated: true, completion: nil)

Going Back:

self.dismissViewControllerAnimated(true, completion: nil)
Tal Zion
  • 6,308
  • 3
  • 50
  • 73
  • 2
    But How to set when I try your code then only set navigation bar but I cannot change its property like bar tint color, title etc. – Berlin Oct 09 '17 at 05:59
  • Not related to this question but you can find the answer here https://stackoverflow.com/questions/26008536/navigationbar-bar-tint-and-title-text-color-in-ios-8 – Tal Zion Oct 09 '17 at 08:42
23

Can you use:

[self.navigationController pushViewController:controller animated:YES];

Going back (I think):

[self.navigationController popToRootViewControllerAnimated:YES];
marrop
  • 279
  • 1
  • 8
  • 3
    Thank you, best way to do it if you already have a navigation controller design in your storyboard. You helped me a lot – phyzalis Mar 04 '14 at 01:11
  • going back is [self.navigationController popViewControllerAnimated:YES]; popToRoot - going all the way back to the 1st viewcontroller – Boris Gafurov Feb 01 '17 at 19:08
2

I had the same problem on ios7. I called it in selector and it worked on both ios7 and ios8.

[self performSelector: @selector(showMainView) withObject: nil afterDelay: 0.0];

- (void) showMainView {
    HomeViewController * homeview = [
        [HomeViewController alloc] initWithNibName: @
        "HomeViewController"
        bundle: nil];
    UINavigationController * navcont = [
        [UINavigationController alloc] initWithRootViewController: homeview];
    navcont.navigationBar.tintColor = [UIColor whiteColor];
    navcont.navigationBar.barTintColor = App_Theme_Color;
    [navcont.navigationBar
    setTitleTextAttributes: @ {
        NSForegroundColorAttributeName: [UIColor whiteColor]
    }];
    navcont.modalPresentationStyle = UIModalPresentationFullScreen;
    navcont.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
    [self.navigationController presentViewController: navcont animated: YES completion: ^ {

    }];
}
methode
  • 5,348
  • 2
  • 31
  • 42
Mohammad Parvez
  • 409
  • 4
  • 12
1

All a [self.navigationController pushViewController:controller animated:YES]; does is animate a transition, and add it to the navigation controller stack, and some other cool navigation bar animation stuffs. If you don't care about the bar animation, then this code should work. The bar does appear on the new controller, and you get an interactive pop gesture!

//Make Controller
DetailViewController *controller = [[DetailViewController alloc] initWithNibName:nil                                                                                 
                                    bundle:[NSBundle mainBundle]];  
//Customize presentation
controller.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
controller.modalPresentationStyle = UIModalPresentationCurrentContext;

//Present controller
[self presentViewController:controller 
                   animated:YES 
                 completion:nil];
//Add to navigation Controller
[self navigationController].viewControllers = [[self navigationController].viewControllers arrayByAddingObject:controller];
//You can't just [[self navigationController].viewControllers addObject:controller] because viewControllers are for some reason not a mutable array.

Edit: Sorry, presentViewController will fill the full screen. You will need to make a custom transition, with CGAffineTransform.translation or something, animate the controller with the transition, then add it to the navigationController's viewControllers.

Ignat
  • 1,142
  • 1
  • 12
  • 22
1

I use this code. It's working fine in iOS 8.

MyProfileEditViewController *myprofileEdit=[self.storyboard instantiateViewControllerWithIdentifier:@"myprofileeditSid"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:myprofileEdit];
[self presentViewController:navigationController animated:YES completion:^{}];
shim
  • 9,289
  • 12
  • 69
  • 108
Anil Prasad
  • 711
  • 1
  • 6
  • 16
1

Swift version : This presents a ViewController which is embedded in a Navigation Controller.

    override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    //  Identify the bundle by means of a class in that bundle.
    let storyboard = UIStoryboard(name: "Storyboard", bundle: NSBundle(forClass: SettingsViewController.self))

    // Instance of ViewController that is in the storyboard.
    let settingViewController = storyboard.instantiateViewControllerWithIdentifier("SettingsVC")

    let navController = UINavigationController(rootViewController: settingViewController)

    presentViewController(navController, animated: true, completion: nil)

}
TheCodingArt
  • 3,436
  • 4
  • 30
  • 53
ioopl
  • 1,735
  • 19
  • 19
1

Swift 3

        let vc0 : ViewController1 = ViewController1()
        let vc2: NavigationController1 = NavigationController1(rootViewController: vc0)
        self.present(vc2, animated: true, completion: nil)
BennyTheNerd
  • 3,930
  • 1
  • 21
  • 16
0

If you use NavigationController in Swift 2.x

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let targetViewController = storyboard.instantiateViewControllerWithIdentifier("targetViewControllerID") as? TargetViewController
self.navigationController?.pushViewController(targetViewController!, animated: true)
Ego Slayer
  • 1,987
  • 2
  • 22
  • 17
0

try this

     let transition: CATransition = CATransition()
    let timeFunc : CAMediaTimingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    transition.duration = 1
    transition.timingFunction = timeFunc
    transition.type = kCATransitionPush
    transition.subtype = kCATransitionFromRight
    self.view.window!.layer.addAnimation(transition, forKey: kCATransition)
    self.presentViewController(vc, animated:true, completion:nil)
tsinghan
  • 425
  • 1
  • 4
  • 11
0

If you didn't set the modalPresentationStyle property (like to UIModalPresentationFormSheet), the navigation bar will be displayed always. To ensure, always do

[[self.navigationController topViewController] presentViewController:vieController 
                                                            animated:YES 
                                                          completion:nil];

This will show the navigation bar always.

Alex Cio
  • 6,014
  • 5
  • 44
  • 74
rakeshNS
  • 4,227
  • 4
  • 28
  • 42
  • Hmm..even with the fixed reference to 'topViewController', I'm still seeing the same behavior. I don't think I'm adding the other view controllers on to the nav stack in any special way. – Jonas Gardner Mar 15 '12 at 17:55
0

One solution

DetailViewController *controller = [[DetailViewController alloc] initWithNibName:nil                                                                                 
                                        bundle:[NSBundle mainBundle]];  

UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
navController.modalPresentationStyle = UIModalPresentationCurrentContext;



[self.navigationController presentViewController:navController 
                                        animated:YES 
                                        completion:nil];
Yatin Sarbalia
  • 211
  • 2
  • 9