91

How Do I set the rootViewController of UINavigationController by a method other than initWithRootViewController?

I want use initWithNavigationBarClass:toolbarClass: to deliver a custom toolbar for my NavigationController, so I don't think I can use initWithRootViewController.

Surfer
  • 1,370
  • 3
  • 19
  • 34
drc
  • 1,905
  • 4
  • 22
  • 28
  • One approach I've just discovered is: [navigationController setViewControllers:[NSArray arrayWithObject:(Pointer to View Controller that should be the root view controller)]]; is this the best way? I assume you should only call this in the AppDelegate file at the didFinishLaunching delegate method, as it seems risky messing with UINavigationController's view controller array after this – drc Apr 25 '13 at 12:46

5 Answers5

167

You can solve this by calling setViewControllers.

Like this:

UINavigationController *navigationController = [[UINavigationController alloc] initWithNavigationBarClass:[MyNavigationBar class] toolbarClass:[UIToolbar class]];

[navigationController setViewControllers:@[yourRootViewController] animated:NO];

Swift version:

let navigationController = UINavigationController(navigationBarClass: MyNavigationBar.self, toolbarClass: UIToolbar.self)

navigationController.setViewControllers([yourRootViewController], animated: false)
Leon Lucardie
  • 9,541
  • 4
  • 50
  • 70
  • Thanks for confirming. This might need to go in a separate question but I assume the initWithNav.. means that all my toolbars will have the same appearance I set in the custom subclass. How do I then have different styled toolbars for different sections of my app? Do I return different toolbars from that custom subclass? Or is there a better approach? – drc Apr 25 '13 at 12:59
  • For that you can use `navigationController.navigationBar.tintColor = [UIColor blackColor];` or however you want to style it in the `-(void)viewDidAppear:animated:` methods of your ViewControllers – Leon Lucardie Apr 25 '13 at 13:12
  • So this would override the fact that in my UIToolBar subclass I'm overriding drawRect and setting a custom background? This is how I implement this: UIImage *backgroundImage = [UIImage imageNamed:@"UIToolBar_Background.png"]; [backgroundImage drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; – drc Apr 25 '13 at 13:18
  • I'm not sure if it overrides as much as a `drawRect` customization, but its the default method for overriding the `UIToolbar` properties of a `UINavigationController`. – Leon Lucardie Apr 25 '13 at 13:20
  • Any idea on this follow up question I posted on an issue I'm encountering. http://stackoverflow.com/questions/16215981/when-subclassing-uitoolbar-to-have-a-custom-background-the-bottom-half-of-toolba – drc Apr 25 '13 at 13:25
30

Knowledge Sharing Using Swift:

Changing root view controller from class other than app delegate.swift

let appdelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var homeViewController = mainStoryboard.instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
let nav = UINavigationController(rootViewController: homeViewController)
appdelegate.window!.rootViewController = nav

Hope this will helpful for someone.

Changing rootviewcontroller With Animation can be achieved with:

UIView.transitionWithView(self.window!, duration: 0.5, options: UIViewAnimationOptions.TransitionFlipFromLeft, animations: {
    self.window?.rootViewController = anyViewController
}, completion: nil)

We can write a generalised method too, similar to this.

pkamb
  • 33,281
  • 23
  • 160
  • 191
MobileGeek
  • 2,462
  • 1
  • 26
  • 46
  • hi @Arvind, can you tell me the best place to put this code? Should it be at the top of AppDelegate.swift so that the variables are globally available? Or perhaps it needs to be within a class somewhere since it's instantiating views? thanks – FireDragon Oct 09 '15 at 21:01
  • Yes, you can use at func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool. Other than you can on any view controller. as you may required when you ask for logout. – MobileGeek Oct 12 '15 at 07:37
  • @Arvind how to deal with animation? No animation is shown and the rootView is shown instantly. – Engnyl Oct 13 '15 at 06:55
  • @Engnyl: I have update the answer. Thanks for your query, that make it more updated. – MobileGeek Oct 13 '15 at 09:48
  • getting nil on self.navigationController – Wasim Ahmed Aug 18 '17 at 16:15
  • This question is "Set rootViewController of UINavigationController by method other than initWithRootViewController" and your answer to use initWithRootViewController? Why? – Andrew Paul Simmons May 20 '19 at 01:57
  • This answer changes the root view controller of the entire window though. The question spefically asks to set the root view controller of a single navigationcontroller. – Leon Lucardie Nov 09 '19 at 20:02
17

this one works for me, hope it helps you,

let rootVC:LoginViewController = self.storyboard?.instantiateViewControllerWithIdentifier("LoginViewController") as! LoginViewController
let nvc:UINavigationController = self.storyboard?.instantiateViewControllerWithIdentifier("RootNavigationController") as! UINavigationController
nvc.viewControllers = [rootVC]
UIApplication.sharedApplication().keyWindow?.rootViewController = nvc
Patel Jigar
  • 2,141
  • 1
  • 23
  • 30
2

In swift 3.0 xcode8.1

in general settings delete in Main Interface: Main <-this after Main Interface:

class AppDelegate...

 var window: UIWindow?

    fun application...

      window = UIWindow(frame: UIScreen.main.bounds)
      window?.makeKeyAndVisible()
      window?.rootViewController = UINavigationController(rootViewController: NewYourController)
artplastika
  • 1,972
  • 2
  • 19
  • 38
Anton Russia
  • 197
  • 1
  • 2
  • 1
    This does not answer the question. You're calling initWithRootViewController, exactly what the question is asking how to avoid. – Robin Daugherty Nov 25 '20 at 22:41
-3
  let storyboard = UIStoryboard(name: "Main", bundle: nil)         
  let yourNewRootView = storyboard.instantiateViewControllerWithIdentifier("yourNewRootView") as? yourNewRootView


   self.window = UIWindow(frame: UIScreen.mainScreen().bounds)

    UIView.transitionWithView(self.window!, duration: 0.1, options: [UIViewAnimationOptions.TransitionFlipFromRight,UIViewAnimationOptions.TransitionFlipFromLeft], animations: 
    {
        // animation

        }, completion: { (finished: Bool) -> () in

            self.window?.rootViewController = nil
            self.window?.rootViewController = yourNewRootView
            self.window?.makeKeyAndVisible()
    })
idris yıldız
  • 2,097
  • 20
  • 22