I've added a Quick Action to my iOS app. When I handle the action, I perform a modal segue I created in the storyboard. If the app is already launched, it comes to the foreground with the destination view controller already visible. However, if the app is not already launched, you see the presenting view controller and then the destination view controller animates into view. I'd like to make it so when you select the Quick Action, you see the destination view controller without it animating into view.
You have to set your ViewController as your app's rootViewController in App Delegate. You can do that like this.
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let rootViewController = mainStoryboard.instantiateViewControllerWithIdentifier("YouControllersStoryBoardIDHere")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window!.rootViewController = rootViewController
self.window!.makeKeyAndVisible()
Put this code in your App Delegat's didFinishLaunchingWithOptions method.
Check your Quick Actions type, corresponding to that call this with appropriate view controller's storyboard id.
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 am using navigationController?.popToRootViewController(animated: true) to dismiss my current view to the previous view. My view controller relationship looks like this.
VC1->VC2
VC1->VC3
VC3->VC2
Whenever the client is in VC2 I want to pop the navigation controller back to VC1. This works fine when the rootviewcontroller is set to VC1. However, when the client uses a segue from VC3 to enter VC2, the rootviewcontroller is set to VC3 and the navigation controller pops to VC3.
I tried to change the rootviewcontroller like this.
// set root view controller
let appdelegate = UIApplication.shared.delegate as! AppDelegate
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let VC1 = mainStoryboard.instantiateViewController(withIdentifier: "VC1") as! FirstViewController
appdelegate.window!.rootViewController = VC1
navigationController?.popToRootViewController(animated: true)
But this actually returns the viewcontroller to the root view controller (VC1) even before the line "navigationController?.popToRootViewController(animated: true)" is executed so there is no animation.
Is there any way to set the rootviewcontroller of a navigation controller without presenting the root view controller right away?
If you put appdelegate.window!.rootViewController = VC1, the stack of controllers has died, you only have in the stack an alone Controller, therefore you can't apply popToRootViewController.
If this is your required navigation, maybe, this post helps you:
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.
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
We are looking to change the way a user logs out of our app. In order to do that, we want to dismiss all the VCs below the current VC and put another VC on top as the root VC. Right now we are doing this which I believe does not dismiss any VC below from memory.
let viewController = storyboard?.instantiateViewController(withIdentifier: "SignIn")
if let unwrappedViewController = viewController {
self.present(unwrappedViewController, animated: true, completion: {})
}
The problem is that the VC that we want to put on top is not embedded in a Navigation Controller or tab bar controller. How would we dismiss the VCs and set the new VC as the main VC as if the user was opening the app for the first time without having previously logged in? We also do want the transition to be animated with whatever animation is normal for that event (modal animation is fine). I have read a bunch of different ways on doing it but I want to know which way is best practice and should be implemented specifically dismissing all VCs and putting a new VC that isn't in a Nav controller on top.
If you can access the UIWindow of the app, you can set its rootViewController property to your sign-in view controller, effectively removing all current view controllers and adding the sign-in view controller instead. Here's an example:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
// Should remove all subsequent view controllers from memory.
appDelegate.window?.rootViewController.dismiss(animated: true, completion: nil)
// Set the root view controller to a new instance of the sign in view controller.
appDelegate.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SignIn")