Is there a way to change root controller when someone is midway into using the app? The way I have it set up right now is that if a new user uses the app they will go into a login page that has the embedded navigation controller. When the user fills out the information they go onto the next page to confirm. The embedded navigation is to go back and change any info. Once they confirm they go to the main page. Now the issue is that the app goes to a different view that already has a Navigation Controller when the user returns and follows some logic. How do I assign the returning user navigation controller when the new user gets into that section? When the user presses back while they are on the blank view they will go back to the confirmation page.
How do I have the confirmation page view get the navigation controller on the top and not the bottom? I'm not sure where to change the Root Navigation Controller but I assume it should be in the prepareForSegue in Confirmation View Controller
if segue.identifier == "showMemoryTable" {
let memoryListVC = segue.destination as? ReturningUserCityDetailTableViewController
memoryListVC?.userData = userData
if userData?.newUser == true {
let newRootViewController = ReturningUserCityTableViewController()
self.navigationController?.viewControllers.first = newRootViewController
let mainStoryBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController: UIViewController = mainStoryBoard.instantiateViewController(withIdentifier: "homeVC")
navigationController?.setViewControllers([viewController], animated: true)
}
I am not sure if I should use setViewControllers but I believe so
If you are aiming to Change the root view controller, you should not do it by by performing a segue, it would be more appropriate to do it like this:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newRootViewController = mainStoryboard.instantiateViewController(withIdentifier: "ReturningUserCityTableViewController") as! ReturningUserCityTableViewController()
let ad = UIApplication.shared.delegate as! AppDelegate
ad.window?.rootViewController = newRootViewController
Note that it changes the whole app root view controller; You could set the desired navigation controller to be the root of the app (obviously you could get them by their storyboard ID).
Related
Im trying to open a certain view from a push notification but i keep losing the nav bar and the back and next references. this what my storyboard looks like this (with the view i want to open)
this is what i have in my AppDelagate:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "notification") as? NotificationViewController
self.window?.rootViewController = vc
What you're doing is completely replacing the root view controller of your application, this means that all the current UI will be discarded.
What you should do instead is to use your knowledge of your application to direct it to the new content. For example, if your root view controller is a navigation controller, you can cast rootViewController to a nav controller and push it (this will fail if your root view controller is something else, like a tab bar controller).
guard let vc = storyboard.instantiateViewController(withIdentifier: "notification") as? NotificationViewController else {
fatalError("Main Storyboard doesn't have a notification controller")
}
guard let nav = self.window?.rootViewController as? UINavigationController else {
return //handle unexpected state
}
nav.push(vc, animated: true)
Another option would be to embed your notification controller into a navigation controller, add a Close button, and present it modally, that way you can present it on top of rootViewController no matter what that controller is.
As we can see in the screenshot your provided, the application's root view controller is the UINavigationController instance.
And according to that, let me offer the next code:
func handleNotification(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "notification") as? NotificationViewController else{
debugPrint("NotificationViewController with identifier 'notification' not found")
return
}
guard let navVC = self.window?.rootViewController as? UINavigationController else{
debugPrint("RootViewController is not an UINavigationController")
return
}
navVC.pushViewController(vc, animated: true) //perhaps your will prefer to use false
}
Beside that, you can use more flexible implementation.
In your AppDelegate post a (NS)Notification when notification intercepted, the relevant view-controller(s) observe the notification, and act when notification broadcasted.
You can also set an identifier to the segue and invoke performSegue method from the observing view-controller
You can set from storyboard -> add view controller -> Embed in navigation controller -> set second view controller -> Attach seque between that controllers. You will see same view controllers like that image .
I need a navigation controller through out my project and my application has a social login initially. Once the authentication is verified user will be pushed to another view, where I display a tabbarcontroller having 2 tabs.
I don't know how to do this in Swift programming. I have embed my viewcontroller in Navigation controller, from here once the authentication is successful how do I push user to tabbar view? Tabbar should also have navigation.
I would like to replicate your idea into what I usually do in the following example.
This is how my storyboard looks like:
As you can see login/signup and Tab bar is not connected with any kind of Segue.
Here Sign in Navigation controller is setup of Initial Controller.
Assign This Navigation Controller an Storyboard ID(e.g.LoginNavigation):
Do the same with Tab Bar Controller, assign Storyboard ID(e.g. HomeTabBar)
Now, you just have to shuffle Root View Controller of the app between Login Nav and Tab Bar.
So if user successfully logs in, changes the application's root view to HomeTabBar using following code:
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let home: UITabBarController = storyboard.instantiateViewControllerWithIdentifier("HomeTabBar") as! UITabBarController
appDelegate.window?.rootViewController = home
And when user logs our, again change the root view to Login Nav:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let entryPoint:UIViewController = mainStoryboard.instantiateViewControllerWithIdentifier("LoginNavigation")
appDelegate.window?.rootViewController = entryPoint
The appDelegate is defined in my constants.swift file :
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
The user logs in and lands on viewNumOne, they fill out their name and address and get to see viewNumTwo and viewNumThree. They now logout. When they log back in I want them to go straight to viewColorBlue (this is where I am having the problem).
(Login Screen)
View Controller with login fields. Once logged in they go to the rootVC which is a TabBar and they land on the first tab which is viewNumOne (this works fine)
(Root)
TabBar:
(First Tab - tabBar[0])
viewNumNavController > viewNumOne (name/address info fields are here) > viewNumTwo > viewNumThree
(Second Tab - tabBar[1])
viewColorNavController > viewColorRed > viewColorBlue > viewColorWhite (logout button is here)
Here is the code I tried but it crashes:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = mainStoryboard.instantiateInitialViewController() as! UITabBarController
tabBarController.selectedIndex = 1
let viewColorNaviCon = tabBarController.viewControllers![1] as! UINavigtionController
let viewColorBlueVC = viewColorNaviCon.topViewController as! ViewColorBlueController
self.presentViewController(viewColorBlueVC, animated: true, completion: nil)
It took me 20 hrs to figure this out so hopefully this will save someone else all that time. What you need to do is reset the TabBar's Navigation Controller's root view controller.
This is the first step. Assume the user landed on viewNumOne where they filled out their name and address. Assuming they properly filled out their name and address, if they logged out and logged back in there wouldn't be any need for them to see this scene again. To present a new scene of vc's you have to first set the tab bar's navigation controller that you want to change the vc's for.
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = mainStoryboard.instantiateViewControllerWithIdentifier("MainTabBarController"
tabBarController.selectedIndex = 1
let viewNumNavController = tabBarController.viewControllers![1] as! ViewNumNavigationController
This is the second step. You have to make an array of the new view controllers you want the user to see.
//Array of view controllers you want to set as the Navigation Controller's new array of VC's
let viewColorRedVC = mainStoryboard.instantiateViewControllerWithIdentifier("ViewColorRedController") as! ViewColorRedController
let viewColorBlueVC = mainStoryboard.instantiateViewControllerWithIdentifier("ViewColorBlueController") as! ViewColorBlueController
let viewColorWhiteVC = mainStoryboard.instantiateViewControllerWithIdentifier("ViewColorWhiteController") as! ViewColorWhiteController
let newArrayOfVCs = [viewColorRedVC, viewColorBlueVC, viewColorWhiteVC]
Now the last step is to change the tab bar's root view controller using the array from above.
//This method is what sets the Navigation Controller's new child views to be presented
viewNumNavController.setViewControllers(newArrayOfVCs, animated: false)
//This method is what sets the exact view controller you want use as the actual root vc (the very first scene the user will see)
viewNumNavController.popToViewController(viewColorRedVC, animated: true)
self.presentViewController(tabBarController, animated: true, completion: nil)
Hope this helps!
In my app, if the user isn't logged, it shows a login controller which is embedded in a navigation controller.
When the user is logged, the app should switch to the other navigation controller to display the app.
How can I switch from one navigation controller to another one when the user is logged. ?
Thanks
I'm checking if the user is log in app delegate :
// Check if user is log
let currentUser = PFUser.currentUser()
if currentUser != nil {
// Do stuff with the user
} else {
// Show the signup or login screen
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let nav = mainStoryboardIpad.instantiateViewControllerWithIdentifier("LogInController") as! UINavigationController
self.window?.rootViewController = nav
}
SOLUTION : looks like it works
When user press logIn button :
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let nav = mainStoryboardIpad.instantiateViewControllerWithIdentifier("MainNavController") as! UINavigationController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = nav
Solution 1
One solution would be to use just a single navigation controller. When the user logs in, you would pop all the view controllers used for logging in and push main view controller on the stack.
Solution 2
Alternatively, you could present a new navigation controller modally on top of the login stuff, with main controller as its root. It would be simply presented on top of it.
Solution 3
You can also consider creating the navigation controller with main view controller first and presenting the login navigation controller on top of it. Then, when user logs in you would just dismiss the login navigation controller revealing the main view controller.
Set your navigation controller storyboard ID
let navigationController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("SecondNavigationController")
self.presentViewController(navigationController, animated: true, completion: nil)
Hope this helps. :)
New iOS developer here. I am working on a project which requires that the user log-in when they first open the app. From then on, I want the app to open directly to the main flow of the app (a tab bar controller in my case). After doing some research, I have come across what seems to be two main ways to do implement this functionality:
1) Conditionally set the root view controller of the app's window in the app delegate. For example:
if userLoggedIn {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let tabBarController: UITabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
self.window?.makeKeyAndVisible()
self.window?.rootViewController = tabBarController
} else {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let logInViewController: LogInViewController = storyboard.instantiateViewControllerWithIdentifier("LogInViewController") as! LogInViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController = logInViewController
}
2) Use a navigation controller as the app's root view controller, and conditionally set the view controllers managed by the navigation controller in the app delegate. For example:
if userLoggedIn {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let tabBarController: UITabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
let navigationController = self.window?.rootViewController as! UINavigationController
navigationController.navigationBarHidden = true
navigationController.setViewControllers([tabBarController], animated: true)
} else {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let tabBarController: ViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as! ViewController
let navigationController = self.window?.rootViewController as! UINavigationController
navigationController.navigationBarHidden = true
navigationController.setViewControllers([tabBarController], animated: true)
}
If I go with the second option, I can easily transition to the app's main flow (let's say a tab bar controller) after I'm done logging in the user. In an appropriate place in the LogInViewController, I can say:
// Transition to tab bar controller
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let tabBarController: UITabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
self.navigationController?.setViewControllers([tabBarController], animated: true)
Pretty easy.
As for the first method, I am not sure how I would transition to the main content of the app after logging the user in.
What I am looking for here is the "best" way to handle login flow. I've listed two methods but maybe there is another that is even better. Also, if the "best" method is the first I have listed, how can I get to my tab bar controller after I finish logging the user in? Thanks!
Those are both fine options. One thing that I've done that has worked well is implemented a custom container view controller as the root of my app (this might be a subclass of my main view controller like a tab bar controller or navigation controller).
In this container view controller, I can put code to display and dismiss a login view controller based on the user's login status. Note: you can also use temporary full-screen views here to hide your app's main content while the login screen is shown/dismissed - this is an easy way to get very smooth app launch transitions.
I particularly like this method, because the rest of the app doesn't need to worry about the details. Your container can act like a normal tab bar controller or navigation controller, but underneath, you get to encapsulate all of the login UI logic in one place.