81

I have system "NavigationViewController -> MyViewController", and I programmatically want to present MyViewController inside a third view controller. The problem is that I don't have navigation bar in MyViewController after presenting it. Can you help me?

var VC1 = self.storyboard.instantiateViewControllerWithIdentifier("MyViewController") as ViewController
self.presentViewController(VC1, animated:true, completion: nil)
fractalwrench
  • 4,028
  • 7
  • 33
  • 49
Yury Alexandrov
  • 2,368
  • 5
  • 17
  • 17

5 Answers5

233

Calling presentViewController presents the view controller modally, outside the existing navigation stack; it is not contained by your UINavigationController or any other. If you want your new view controller to have a navigation bar, you have two main options:

Option 1. Push the new view controller onto your existing navigation stack, rather than presenting it modally:

let VC1 = self.storyboard!.instantiateViewControllerWithIdentifier("MyViewController") as! ViewController
self.navigationController!.pushViewController(VC1, animated: true)

Option 2. Embed your new view controller into a new navigation controller and present the new navigation controller modally:

let VC1 = self.storyboard!.instantiateViewControllerWithIdentifier("MyViewController") as! ViewController
let navController = UINavigationController(rootViewController: VC1) // Creating a navigation controller with VC1 at the root of the navigation stack.
self.present(navController, animated:true, completion: nil)

Bear in mind that this option won't automatically include a "back" button. You'll have to build in a close mechanism yourself.

Which one is best for you is a human interface design question, but it's normally clear what makes the most sense.

stefandouganhyde
  • 4,494
  • 1
  • 16
  • 13
  • 1
    How can I make it so that the new view controller will be brought from Right to Left, rather than from Bottom up? Thanks – vincwng Jul 31 '16 at 16:18
  • 6
    Ok. But how can i close the modal? – Peter Kreinz Oct 19 '16 at 08:41
  • MyViewController (ViewController) already linked to NavigationController via StoryBoard. Then the Option 1, Not works, Its present navigation controller without navigation bar! – kiran Mar 02 '19 at 15:44
  • 1
    Write this line of code if you see double NavigationBar. `navController.isNavigationBarHidden = true` – Neeraj Joshi Jun 10 '19 at 09:41
  • @PeterKreinz probably a bit late, but it might help somebody. Using XCode 13, and a simulator of an iPhone 7 with iOS 11.4 I found the above solution worked but wasn't displaying `VC1` modally, however when I ran the same code on a actual iPhone the view was displayed modally – Gavin Feb 18 '22 at 09:14
  • The second option does not work with iPhone 12 or iPhone XR. It works for iPhone 7 and iPod 7th Generation. Is there a solution which would work universally? – es1 Oct 13 '22 at 14:10
17

SWIFT 3

let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "MyViewController") as! MyViewController
let navController = UINavigationController(rootViewController: VC1)
self.present(navController, animated:true, completion: nil)
Yaroslav Dukal
  • 3,894
  • 29
  • 36
15

My navigation bar was not showing, so I have used the following method in Swift 2 iOS 9

let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("Dashboard") as! Dashboard

// Creating a navigation controller with viewController at the root of the navigation stack.
let navController = UINavigationController(rootViewController: viewController)
self.presentViewController(navController, animated:true, completion: nil)
Andreas Kraft
  • 3,754
  • 1
  • 30
  • 39
Vinod Joshi
  • 7,696
  • 1
  • 50
  • 51
2

The accepted answer is great. This is not answer, but just an illustration of the issue.

I present a viewController like this:

inside vc1:

func showVC2() {
    if let navController = self.navigationController{
        navController.present(vc2, animated: true)
    }
}

inside vc2:

func returnFromVC2() {
    if let navController = self.navigationController {
        navController.popViewController(animated: true)
    }else{
        print("navigationController is nil") <-- I was reaching here!
    }
}

As 'stefandouganhyde' has said: "it is not contained by your UINavigationController or any other"

new solution:

func returnFromVC2() {
    dismiss(animated: true, completion: nil)
}
mfaani
  • 33,269
  • 19
  • 164
  • 293
1

I used an extension to UIViewController and a struct to make sure that my current view is presented from the favourites

1.Struct for a global Bool

struct PresentedFromFavourites {
static var comingFromFav = false}

2.UIVeiwController extension: presented modally as in the second option by "stefandouganhyde - Option 2 " and solving the back

extension UIViewController {
func returnToFavourites()
{
    // you return to the storyboard wanted by changing the name
    let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
    let mainNavigationController = storyBoard.instantiateViewController(withIdentifier: "HomeNav") as! UINavigationController
    // Set animated to false
    let favViewController = storyBoard.instantiateViewController(withIdentifier: "Favourites")
    self.present(mainNavigationController, animated: false, completion: {
        mainNavigationController.pushViewController(favViewController, animated: false)
    })

}
// call this function in viewDidLoad()
// 
func addBackToFavouritesButton()
{
    if PresentedFromFavourites.comingFromFav
    {
        //Create a button
        // I found this good for most size classes
        let buttonHeight = (self.navigationController?.navigationBar.frame.size.height)! - 15
        let rect = CGRect(x: 2, y: 8, width: buttonHeight, height: buttonHeight)
        let aButton = UIButton(frame: rect)
        // Down a back arrow image from icon8 for free and add it to your image assets  
        aButton.setImage(#imageLiteral(resourceName: "backArrow"), for: .normal)
        aButton.backgroundColor = UIColor.clear
        aButton.addTarget(self, action:#selector(self.returnToFavourites), for: .touchUpInside)
        self.navigationController?.navigationBar.addSubview(aButton)
        PresentedFromFavourites.comingFromFav = false
    }

}}
Atka
  • 547
  • 4
  • 7