In some cases I want my app to present a different view controller than the one that normally loads (in this case AltView rather than MainView), but I can't figure out how to do it. I tried like this:
let storyboard = UIStoryboard.init(name: "Alt", bundle: nil)
let nav = storyboard.instantiateViewControllerWithIdentifier("AltView")
let mainStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
let rootVC = mainStoryboard.instantiateViewControllerWithIdentifier("MainView")
self.window!.rootViewController = rootVC
window!.makeKeyAndVisible()
self.window!.rootViewController?.presentViewController(nav, animated: true, completion: nil)
But nothing happens, the screen is just blank, no errors or warnings are being reported.
EDIT: AltView is an UINavigationController with an embedded UIViewController. The viewDidLoad() method of AltView's embedded view controller is being run, but its viewWillAppear() method is not.
What am I doing wrong?
Just set the window controller like this
let mainStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
let nav = storyboard.instantiateViewControllerWithIdentifier("AltView")
self.window!.rootViewController = nav
If u want to change the controller change the window rootviewcontroller again with same code just change the identifier to the one that you want of the controller and you don't need this statement `self.window!.rootViewController?.presentViewController(nav, animated: true, completion: nil)
If you face any issues let me know
Related
I am opening new viewcontroller like
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let view_controller1 = storyBoard.instantiateViewController(withIdentifier: "incident_view_id") as! IncidentViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//self.present(registerViewController, animated: true)
let navigationController = UINavigationController.init(rootViewController: view_controller1)
appDelegate.window?.rootViewController = navigationController
Which works fine,
Now when I press a button I need to close current view and go back previous view, I tired
self.navigationController?.popToRootViewController(animated: true)
But not works, I tried this too
self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
But same result.
You are presenting your ViewController in a wrong way. The following line tells the application to no matter what ViewControllers you have opened, just throw it out and assign the UINavigationController what you are creating, as the rootViewController. So the reason your code, the dismiss, is not working because there are no other ViewControllers behind your current one.
appDelegate.window?.rootViewController = navigationController // Wrong
This usually goes into the beginning of the applications, where you define with which UIViewController you want to start your application. I believe you are calling the first code chunk you posted from a UIViewController. So what you need to do instead of creating a new UINavigationController and assigning it to the rootViewController, you just use the UIViewControllers navigation controller to push the next UIViewController.
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let view_controller1 = storyBoard.instantiateViewController(withIdentifier: "incident_view_id") as! IncidentViewController
navigationController?.pushViewController(view_controller1, animated: true)
I am changing a menu VC over from StoryBoard to programatic operation.
When I want to load another VC I was using the Action Segue "Show".
The temporary code I am using works but pops the VC over the top. Can you action the "Show" equivalent programatically, and if so how?
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "SunriseSunsetResultsViewController")
self.present(newViewController, animated: true, completion: nil)
To do what a Show segue used to do, replace present with show:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "SunriseSunsetResultsViewController")
self.show(newViewController, sender: self)
Note, however, that this will do the same thing as present unless self.navigationController is not nil. In other words, you cannot do the sideways navigation you were doing before unless a navigation controller is in charge of the interface.
Instead of show you could say pushViewController etc., but the same caveat applies. Only a navigation controller can do what you were doing previously.
I have created a popup displaying a list in which I send the text to another viewcontroller, but when I close the popup, the Navigation Item disappears, and I have already searched for nothing to solve this problem. The code that sends the selected list item in the popover is this:
Shared.shared.filialNome = self.filiais[indexPath.row].razaoSocial
self.recebeCodigo = self.filiais[indexPath.row].codigo
Shared.shared.codigoFilial = self.recebeCodigo
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "AniversarioViewController") as! AniversarioViewController
self.present(newViewController, animated: true, completion: nil)
Type of following = Modal
I have tried to call Present as Popover but the error persists, it seems that it does not close the VC completely, somebody can help me.
Before opening the popover and
After opening the popover
It seems like, as you are presenting the view controller (and ViewControllers do not have navigation item until we embed it in navigation controller).
So you can embed the same ViewController in navigation controller in storyboard and then get the reference for that navigation controller and present the navigation controller like
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let navController = storyBoard.instantiateViewController(withIdentifier: "YourNavigationControllerIdentifier") as! UINavigationController
self.present(navController, animated: true, completion: nil)
Or if you don't want to embed you can do programmatically like
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "AniversarioViewController") as! AniversarioViewController
let navController = UINavigationController.init(rootViewController: newViewController)
self.present(navController, animated: true, completion: nil)
I'm using following code to programmatically navigate to another ViewController. It works fine, but it some how hides the navigation bar. How do I fix this? (the navigation bar is created by embeding the ViewController in the navigation controller if that matters.)
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("nextView") as NextViewController
self.presentViewController(nextViewController, animated:true, completion:nil)
Swift 5
The default modal presentation style is a card. This shows the previous view controller at the top and allows the user to swipe away the presented view controller.
To retain the old style you need to modify the view controller you will be presenting like this:
newViewController.modalPresentationStyle = .fullScreen
This is the same for both programmatically created and storyboard created controllers.
Swift 3
With a programmatically created Controller
If you want to navigate to Controller created Programmatically, then do this:
let newViewController = NewViewController()
self.navigationController?.pushViewController(newViewController, animated: true)
With a StoryBoard created Controller
If you want to navigate to Controller on StoryBoard with Identifier "newViewController", then do this:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "newViewController") as! NewViewController
self.present(newViewController, animated: true, completion: nil)
SWIFT 4.x
The Strings in double quotes always confuse me, so I think answer to this question needs some graphical presentation to clear this out.
For a banking app, I have a LoginViewController and a BalanceViewController. Each have their respective screens.
The app starts and shows the Login screen. When login is successful, app opens the Balance screen.
Here is how it looks:
The login success is handled like this:
let storyBoard: UIStoryboard = UIStoryboard(name: "Balance", bundle: nil)
let balanceViewController = storyBoard.instantiateViewController(withIdentifier: "balance") as! BalanceViewController
self.present(balanceViewController, animated: true, completion: nil)
As you can see, the storyboard ID 'balance' in small letters is what goes in the second line of the code, and this is the ID which is defined in the storyboard settings, as in the attached screenshot.
The term 'Balance' with capital 'B' is the name of the storyboard file, which is used in the first line of the code.
We know that using hard coded Strings in code is a very bad practice, but somehow in iOS development it has become a common practice, and Xcode doesn't even warn about them.
You should push the new viewcontroller by using current navigation controller, not present.
self.navigationController.pushViewController(nextViewController, animated: true)
According to #jaiswal Rajan in his answer. You can do a pushViewController like this:
let storyBoard: UIStoryboard = UIStoryboard(name: "NewBotStoryboard", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "NewViewController") as! NewViewController
self.navigationController?.pushViewController(newViewController, animated: true)
So If you present a view controller it will not show in navigation controller. It will just take complete screen. For this case you have to create another navigation controller and add your nextViewController as root for this and present this new navigationController.
Another way is to just push the view controller.
self.presentViewController(nextViewController, animated:true, completion:nil)
For more info check Apple documentation:-
https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/#//apple_ref/doc/uid/TP40006926-CH3-SW96
OperationQueue.main.addOperation {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "Storyboard ID") as! NewViewController
self.present(newViewController, animated: true, completion: nil)
}
It worked for me when I put the code inside of the OperationQueue.main.addOperation, that will execute in the main thread for me.
All other answers sounds good, I would like to cover my case, where I had to make an animated LaunchScreen, then after 3 to 4 seconds of animation the next task was to move to Home screen. I tried segues, but that created problem for destination view. So at the end I accessed AppDelegates's Window property and I assigned a new NavigationController screen to it,
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let homeVC = storyboard.instantiateViewController(withIdentifier: "HomePageViewController") as! HomePageViewController
//Below's navigationController is useful if u want NavigationController in the destination View
let navigationController = UINavigationController(rootViewController: homeVC)
appDelegate.window!.rootViewController = navigationController
If incase, u don't want navigationController in the destination view then just assign as,
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let homeVC = storyboard.instantiateViewController(withIdentifier: "HomePageViewController") as! HomePageViewController
appDelegate.window!.rootViewController = homeVC
The above code works well but if you want to navigate from an NSObject class, where you can not use self.present:
let storyBoard = UIStoryboard(name:"Main", bundle: nil)
if let conVC = storyBoard.instantiateViewController(withIdentifier: "SoundViewController") as? SoundViewController,
let navController = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
navController.pushViewController(conVC, animated: true)
}
We have two storyboards in our app. The default view in storyboard #1 assumes the user has previously supplied valid credentials. If they have not done so we "redirect" to the login screen in storyboard #2:
let storyboard = UIStoryboard(name: "Authentication", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("LoginController") as UIViewController
presentViewController(controller, animated: true, completion: nil)
This works - but there is a flicker when this code runs where the default view briefly appears prior to the login view being displayed. How can you perform this action without a flicker?
Instead of presenting LoginController you have to set the respective ViewController as rootviewcontroller to the window in Appdelegate itself as folllows:
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
//Check for credentials,if value available make LoginStatus as true
if LoginStatus == true{
//Change Storyboard name "Main" to your "storyboard #1" name.
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
//Change Viecontroller name "My_Offer" to your "DefaultViewController name" name.
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("My_Offer") as UIViewController
let navigationController = UINavigationController(rootViewController: vc)
self.window!.rootViewController = navigationController
}else{
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Authentication", bundle: nil)
let vc = mainStoryboard.instantiateViewControllerWithIdentifier("LoginController") as UIViewController
let navigationController = UINavigationController(rootViewController: vc)
self.window!.rootViewController = navigationController
}
self.window!.makeKeyAndVisible()
This will prevent from displaying default view before presenting LoginController.
Or else
In storyboard #1 create a DummyViewController(UIViewController) and make it as InitialViewController and set a Background image(Your SplashScreen Image) to DummyViewController .In viewdidload check for credentials,If You have value
let storyboard = UIStoryboard(name: "storyboard #1", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("default view ") as UIViewController
presentViewController(controller, animated: true, completion: nil)
if no credentials go with your given code
let storyboard = UIStoryboard(name: "Authentication", bundle: nil)
let controller = storyboard.instantiateViewControllerWithIdentifier("LoginController") as UIViewController
presentViewController(controller, animated: true, completion: nil)
this too prevents flicker but it is not good way to do.I suggest First Method setting rootviewcontroller.This may help you.Give it a try.
My suggestion is to set launch screen viewcontroller as rootviewcontroller of the application until the all your deciding factor get executed. This is one of the finest approach for async operation.