I have what I am calling a one time onboard set of UIViews that ask the user a couple questions to configure my iOS app correctly.
When the user has answered the onboarding questions I would like to segue to the UITabBarController Home screen, this is the same screen that will always appear every subsequent time the app opens after onboarding is complete. I do not have an Initial UIViewController set in my Storyboard, this, in my AppDelegate is how I go to the correct view, every time the app loads:
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
if Settings.sharedInstance.onboardComplete{
let vc = storyboard.instantiateViewController(withIdentifier: baseTabBarStoryboardIdentifier) as! UITabBarViewController
self.window?.rootViewController = vc
} else{
self.window?.rootViewController = storyboard.instantiateViewController(withIdentifier: onboardStoryboardIdentifier) as! OnboardNavigationController
}
self.window?.makeKeyAndVisible()
This works fine, and I am able to load the UITabBarViewController which contains all my app's primary UIViews without any issues.
I would like to achieve this same "segue" from a UIButton TouchUpInside action. This segue would occur in a set of UIViews in a UINavigationViewController that has no connection to the main app UIViews contained in aforementioned UITabBarViewController, here is a screenshot of my Storyboard to give some context to this statement, you can see the onboarding UIViews circled in red, the main app UIViews contained in a UITabBarViewController are circled in blue:
I have tried the same code as above in my AppDelegate in my UIButton action outlet implementation, I create a UIWindow instance, I get the Storyboard, I instantiate the UITabBarViewController, I set the UIWindow rootViewController. I am not able to figure out a way to transition to my main app UITabBarViewController after the user completes the Onboarding questions
Try this
let appDelegate = UIApplication.shared.delegate as? AppDelegate
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeController = mainStoryboard.instantiateViewController(withIdentifier:baseTabBarStoryboardIdentifier) as! UITabBarViewController
appDelegate?.window?.rootViewController = homeController
Related
I have a background task that runs from AppDelegate, when it needs to it displays notifications.
When these notifications are tapped they should direct the user to the ViewController that relates to the notification.
I was wondering if it was possible to perform segues from AppDelagate.
My ViewControllers are in a navigation controller. I'm guessing I have to instantiate my root view controller and perform segue there, just not sure how to do that from appdelegate.
Edit:
Here is my code so far, it works it just isn't embedded in my navigation controller
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ConversationVC") as? conversationTableViewController {
if let window = self.window, let rootViewController = window.rootViewController {
var currentController = rootViewController
while let presentedController = currentController.presentedViewController {
currentController = presentedController
}
currentController.present(controller, animated: true, completion: nil)
}
}
You can't segue from a storyboard that isn't loaded yet.
Depending on your case you could:
1: Send data from the AppDelegate to the initial root view controller of your current storyboard and from there, create multiple segues to the respectable VC depending on the data.
OR
2: Create multiple storyboards (one for each case) and launch the appropriate ones from the AppDelegate according to the notification.
Edit: Need to see the storyboard. For the variable, add it to conversationTableViewController and set it up just before you present it:
controller.myVar = "someValue"
self.window.rootViewController = controller
self.window.makeKeyAndVisible()
I have a TabBarController with two tabs Cases & Settings
I would like to take the user to CaseSummaryTVC which is nested like this
TabBarController > Cases (NavigationController, Storyboard Id = 'tvcNav' ) > CasesTVC (TableViewController) > CaseSummaryTVC (TableViewController, Storyboard Id = 'CaseSummaryTVC').
I am using the below code in AppDelegate, which takes me to the 'CaseSummaryTVC' but doesn't show the TabBar on the bottom.
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let navController = mainStoryboard.instantiateViewController(withIdentifier: "tvcNav") as! UINavigationController
let caseSummaryTVC = mainStoryboard.instantiateViewController(withIdentifier: "CaseSummaryTVC") as! CaseSummaryTVC
navController.pushViewController(caseSummaryTVC, animated: true)
self.window?.rootViewController = navController
self.window?.makeKeyAndVisible()
It looks like you're setting your window's rootViewController to be 'navController', which doesn't seem to be wrapped in a UITabBarController.
I'm not sure what your storyboard looks like, but it sounds like you have the view hierarchy setup correctly there.
You could do one of the following:
1) Remove the programmatic view controller instantiation and have the storyboard take care of setting the rootViewController to the UITabBarController.
2) Instantiate the UITabBarController programmatically like you have done here with the other view controllers, and make sure it's set up to have the navController as one of it's tabs.
I have some ViewControlls for settings, info etc.
Users can close the app settings ViewController open(I mean popover the ViewController).
When local notification is received I want the the app go to the root viewcontroller and dismiss any popovers.
EDIT
this answer is only good if the VC you are trying to go back to does not need any special initialization, since this method creates a new instance of it. keep that in mind.
Try this method, it will remove anything in your stack of View Controllers and make a specific View Controller presented on screen:
func dismissAllAndNavigate(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let window = appDelegate.window
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let rootController = mainStoryboard.instantiateViewController(withIdentifier: "some identifier") as! UIViewController
window?.rootViewController = rootController
}
Just make sure that the name of the storyboard is correct and the identifier of the view controller in that storyboard is defined.
I have a TapBarViewController with three Taps in my project.
Now I am trying to put a normal FirstViewController in front of the TapBar ViewController when the application launches.
The FirstViewController should have three buttons for one of the individual Taps of the TapBarViewController.
How can I show the individual Taps of the TapBarViewController by pressing one of the three buttons?
Screenshot
This is the exact answer you are looking for.
Steps:
Add a UIViewcontroller and embed with UINavigationViewController (Editor -> EmbedIn -> NavigationController).
Add Three button + 1 Button (Navigate to TabViewController).
Drag and drop UITabBarController to the storyboard it comes with one default ViewController and place a UILabel named as 'ButtonOneClicked'.
Create Two more ViewControllers and named as 'ButtonTwoClicked' and 'ButtonThreeClicked'.
Connect 'ButtonOne' with FirstViewController and set segue as Show and repeat the same for rest two.
Click on each segue and provide an unique Identifier name.
Then connect the UITabBarController with each UIViewController and choose viewcontrollers
Create a ButtonAction to the Tab Button.
Copy paste the below code in that action.
#IBAction func tabClicked(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "Tab") as! UITabBarController
appDelegate.window?.rootViewController = initialViewController
appDelegate.window?.makeKeyAndVisible()}
Hope this helps you!!
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.