I have a problem with changing root in my app.
Design of my app.
After I login into app I would like to change root vc to UITabBarViewController to clean a stack.
I've faced multiple problems.
Setting vc to tab bar on apply login action -> or in bottom vc:
self.performSegue(withIdentifier: "goToMainTabBar", sender: nil)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let vc = segue.destination as? TabBarViewController {
UIApplication.shared.keyWindow?.rootViewController = vc
}
}
The app going to crash with:
Application tried to present modal view controller on itself. Presenting controller is TabBarViewController
Next problem is if we set a root in TabBarViewController viewDidLoaded.
UIApplication.shared.keyWindow?.rootViewController = self
Tab bar items embaded in UINavigationController doesnt have Navigation controller in it selfs, so the nav vc is not instantiated ? Becouse wheenver I will enter into item vc child -> I can't back any more.
If i won;t change a root vc there everything is fine.
For 1) you can't present a view controller using a segue and then use it to replace the root view controller in the prepare. You will need to instantiate the tab view controller from the storyboard and then replace the root view controller.
Something like this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "TabController")
UIApplication.shared.keyWindow?.rootViewController = vc
(assuming the storyboard is called 'Main' and you give the tab controller the storyboard ID of 'TabController'.
I'm not quite clear on what the issue is for 2.
However as a general note I would approach this differently and instead of having the login controller as your initial view controller have the tab bar as the initial controller and then just present the login controller the first time the app starts. That way you avoid replacing the root controller at all and it's all more controlled.
Related
I have a popover view which is simply a stack of UIButtons.
The popover is presented from a view controller (Records) which is itself inside a NavigationController.
I need the buttons in popover view to be able to push other views on top of the navigation stack.
Here's how I prepare the segue for the popover in the Records view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popoverSegue" {
let dest = segue.destination as! PopoverViewController
dest.navController = navigationController
dest.modalPresentationStyle = .popover
dest.popoverPresentationController?.barButtonItem = addButton
dest.popoverPresentationController?.delegate = self
}
}
Then inside the popoverViewController I got a bunch of IBAction functions where I need to push other views on top of the navController that was set above.
let editor = EditorViewController(nibName: "EditorViewController", bundle: nil)
navController?.pushViewController(editor, animated: true)
This kina works and the editor view shows up with a nav bar and all, but as soon as I tap on the view or try to scroll, it just gets dismissed.
How can I prevent that dismiss thing? I did try setting isModalInPresentation. It didn't work for me.
Answering, as per OP's comments...
The proper approach is to have your "popover" controller tell the presenting controller to push a new VC onto the navigation stack.
This can be done in a few different ways, but most commonly by using either the protocol/delegate pattern or with closures.
So I have an if statement that has 2 outcomes, rootViewController becomes loginViewController or mainSearchViewController. The storyboard for mainSearchViewController has an embedded TabViewController and a NavigationViewController. However, by setting the root view controller, I lose access to both the TabViewController and a NavigationViewControllerand its only the mainSearchViewController that is active. Here is my code:
func setRootViewController() {
if Auth.auth().currentUser != nil {
let mainSearchViewController = storyboard?.instantiateViewController(withIdentifier: Constants.Storyboard.mainSearchViewController)
view.window?.rootViewController = mainSearchViewController
view.window?.makeKeyAndVisible()
} else {
let loginSearchViewController = storyboard?.instantiateViewController(withIdentifier: Constants.Storyboard.loginViewController)
view.window?.rootViewController = loginSearchViewController
view.window?.makeKeyAndVisible()
Lose access to Tab Bar Controller and Nav Controller when making the root view controller the view on the very right
Edit: I have tried to set the rootViewController to the Tab Controller, this allows me to use the tab functionality but I still don't have access to the Nav Controller. Same goes for the Nav Controller, it works when it is the root view controller but there is no Tab Controller functionality
Edit 2: In the viewDidLoad() of the mainSearchViewControllernavigationController?.isNavigationBarHidden = false` and I have the root view controller as the Tab Bar Controller. I can access the tab icons, and I can see the navigation bar, but the navigation functionality when tapping on a cell doesn't work.
Changing rootViewController is likely causing your problem since tabViewController probably doesn't have loginViewController as a tab.
If you need to display loginViewController based on an if statement, it's better practice to show it using something like:
navViewController.pushViewController(loginViewController, animated: true)
In my iOS app, in a viewController I try to open a specific view in Tab Bar Controller.
I use a performSegue.
First I try to navigate straight to the specific view , but in this case the tab bar disappear
So I try to navigate to the tabViewController, and this lead me to the defult view (the first)
any idea how to navigate to a specific view in TabBarController ?
the performSegue I use:
self.performSegue(withIdentifier: "goToMain", sender: self)
//"goToMain" is my indentipier to the storyboard Segue
I use swift 4
with this code, you don't need segues, you can use when you push some button
let VC1 = self.storyboard!.instantiateViewController(withIdentifier: "tabBarController") as! tabBarLoginViewController
VC1.selectedIndex = 2 //this line says that the view that appears will be third of you tab bar controller
self.navigationController!.pushViewController(VC1, animated: true)
if you want to use segue use this, the segue needs to point of tab bar controller, not a view of tab bar controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "goToMain") {
let vc = segue.destination as! TabBarController
vc.selectedIndex = 2
}
}
hello my controller is connected to tabBar and navigationController now I want to show the controller over the current context then move to another controller B which must show the tab bar and back button of the navigation , currently i am doing segue its showing me black background.
Below is my UIStoryBoard layout.
i am moving to next viewController using segue like below
performSegue(withIdentifier: "second", sender: self)
Select the segue and change it's attributes as following
//
set id for the VC and use this instead of a segue after you dismiss the model
let vc = self.storyboard?.instantiateViewController(withIdentifier: "Id")
self.presentingViewController?.navigationController?.pushViewController(vc!, animated: true)
I'm trying to trigger a modal view from the AppDelegate every time the app is opened. I can see my breakpoint being hit, but the modal never shows. I'm including an image of my storyboard in case it matters. It's a fairly simple app right now with a 2 tab tab bar controller.
This is the code I have in the AppDelegate to trigger it.
let newVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginView")
let view = window?.rootViewController as! UITabBarController
view.selectedViewController?.show(newVC, sender: nil)
It seems newVC is not in the tab bar's controllers array, and you're attempting to modally present it from the selectedViewController in AppDelegate where there probably isn't a selected view controller yet.
One solution is to present newVC after viewDidLoad of the selected view controller (view controller at selectedIndex). If the presentation must take place before any of the tab bar's view controllers are loaded, then you might wanna set it as the window's root view controller and set the root to be the tab bar once newVC has finished its business.