I wonder how I can check what view controller that is currently displayed.
When a user recivies a notification and press on it I want to take the user to a certain VC. But only if the user is not already there.
I am using this when I get a notification:
if let tabBarController = self.window!.rootViewController as? CustomTabBarController {
let navInTab:UINavigationController = tabBarController.viewControllers?[0] as! UINavigationController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationViewController = storyboard.instantiateViewController(withIdentifier: "EventVc") as? EventsViewController
navInTab.pushViewController(destinationViewController!, animated: true)
tabBarController.selectedIndex = 0
}
I dont want to run this code if the user already is in EventVc
Also, can I run the code above if the user already is in tab 0 but in a different VC than EventVc?
And if it is any help my app is built like this:
(root) TabBar
(tab1) -> navigation controller -> vc -> vc...
(tab2) -> navigation controller -> vc -> vc...
(tab3) -> navigation controller -> vc -> vc...
(tab4) -> navigation controller -> vc -> vc...
this function should solve your problem, just send index number as an argument (forexample: 0 for tab1, 1 for tab2 etc.) at it navigates you selectedIndex ViewController.
// Navigation TabIndex TabBar View Controller
fileprivate func goTabIndex(index: Int) {
let storyboard = UIStoryboard(name: "yourTabbarStoryboardID", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "EventVc") as! UITabBarController
tabBarController.selectedIndex = index
self.window?.makeKeyAndVisible()
DispatchQueue.main.async {
self.window?.rootViewController?.present(tabBarController, animated: false)
}
}
You can find the Presenting ViewController like this;
let presentingVC = self.window?.rootViewController?.presentingViewController
Presented ViewController;
let presentedVC = self.window?.rootViewController?.presentedViewController
Related
I have UIContainerView inside which I have UINavigationController and other VC embedded in UINavigationController (7 of them).
So, it looks like this:
On that 7 screens inside UINavigationController I'm calling a popup screen which then should redirect to other screen, from which user can perform back segue to the VC popup was called from.
So, user journey inside UINavigationController will look like:
Opened VC1(2,3,5,6,7) -> Called popup VC -> Pressed button -> opened VC4 -> pressed navigation back button -> returned to VC1.
Here's my code:
#IBAction func didPressAuthors(_ sender: UIButton) {
self.dismiss(animated: true) {
if let navigation = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
let vc1 = self.storyboard!.instantiateViewController(withIdentifier: "FirstVC")
let vc2 = self.storyboard!.instantiateViewController(withIdentifier: "SecondVC")
let vc3 = self.storyboard!.instantiateViewController(withIdentifier: "ThirdVC")
let vc4 = self.storyboard!.instantiateViewController(withIdentifier: "FourthVC")
let vc5 = self.storyboard!.instantiateViewController(withIdentifier: "FifthVC")
let finalVC = self.storyboard!.instantiateViewController(withIdentifier: "Authors")
let userJourney = self.defaults.array(forKey: DefaultKeys.screenID.rawValue)
for vcName in userJourney! {
switch String(describing: vcName) {
case "FirstVC":
self.journeyVC.append(vc1)
case "SecondVC":
self.journeyVC.append(vc2)
case "ThirdVC":
self.journeyVC.append(vc3)
case "FourthVC":
self.journeyVC.append(vc4)
case "FifthVC":
self.journeyVC.append(vc5)
default:
self.journeyVC.append(finalVC)
}
}
self.journeyVC.append(finalVC)
navigation.setViewControllers(self.journeyVC, animated: true)
}
}
}
Problem:
When I didn't have UINavigationController inside UIContainerView this code worked just fine, but after I had added Container View - it stopped. Dismiss func is called, but nothing happens. What I'm missing? Should I change how VC is presented?
Would be grateful if anyone could help me fix this issue. Many thanks and have a nice weekend!
Your current root isn't the navigation here
if let navigation = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
it's a usual VC that the navigation is inserted as a child so try
if let root = UIApplication.shared.keyWindow?.rootViewController as? RootVC {
let nav = root.children![0] as! UINavigationController
I have implemented firebase notification in my app. When I click the notification i want to open specific vc. The hierarchy of vc is this,
TabBarController -> TabBarVC1 -> 1VC -> 2VC
Now, I want to go to 2VC when I click the notification. I have tried the code it goes fine but the hierarchy of VC's disturbs, when I moves there then it does not comes back. This is how i open 2VC.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "2VC")
self.present(controller, animated: true, completion: nil)
I want it to open 2VC but its hierarchy should not be disturb.
When I click back button on 2VC than it should move back to 1VC.
Do this
let vc1 = // alloc vc 1
let vc2 = // alloc vc 2
let vc3 = // alloc vc 3
let nav_Controllr = // alloc UINavigationController
// Now add your previous vc in NavigationController first
nav_Controllr.viewControllers.append(vc1)
nav_Controllr.viewControllers.append(vc2)
// Now push to the vc where you wanted navigate
nav_Controllr.pushViewController(vc3, animated: true)
Now your navigation stack is like this
vc1 -> vc2 -> vc3
when you pop your controller then it always be in this flow.
vc3 => vc2 => vc1
To have a back button then you need to make the root vc of the tabBar a navigationController
Entry Point -> TabBar -> Tab1 -> NavigationController - > VC1 -> VC2
then use this from vc1
self.navigationController?.pushViewController(vc2, animated: true)
if you want to open it from AppDelelgate call back of notification receive then use
if let tab = self.window?.rootViewController as? UITabBarController {
let vc1 = //////
let vc2 = //////
let nav = tab.viewControllers![0] as! UINavigationController
nav.viewControllers = [vc1,vc2]
}
I have a UITabBarController and all my other view controllers are connected to it. Now I want to show one my controller as:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: ViewController = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
but when I tried to:
let rootViewController = self.window?.rootViewController as! UINavigationController
rootViewController.pushViewController(vc, animated: true)
it gave me the next error:
Could not cast value of type 'UITabBarController' (0x1a899b818) to 'UINavigationController'
Later I've tried to do:
let rootViewController = self.window?.rootViewController as! UITabBarController
but in this case I get
UITabBar has no member pushViewController
How can I show/push my ViewController so it will appear with UINavigationBar and inside of UITabBar?
You need to place each of your view controllers inside a navigation controller.
E.g. currently you have a TabBarViewController
and two view controllers:
ViewControllerA
ViewControllerB
What you need to do is to embed each of them inside a navigation controller so you would have:
UINavigationController -> ViewControllerA
UINavigationController -> ViewControllerB
In order to push a new controller you would do:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc: ViewController = storyboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
let navViewController = myTabBar.selectedViewController as? UINavigationController
navViewController?.pushViewController(vc, animated: true)
Could not cast value of type 'UITabBarController' (0x1a899b818) to 'UINavigationController'
Your root view controller is of type UITabBarController.
Therefore you have to use the appropriate methods of this class and not UINavigationController.
To set view controllers use either
var viewControllers: [UIViewController]? or
func setViewControllers([UIViewController]?, animated: Bool).
To have a navigation bar you have to instantiate a UINavigationController and add your view controller to this navigation controller.
Then add your navigation controller to your UITabBarController with via one of the above options.
If your class is UITabBarController
You can add this:
private func showViewController() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "queueTableViewController") as? QueueTableViewController else { return }
let navVC = self.selectedViewController as? UINavigationController
navVC?.pushViewController(vc, animated: true)
}
This will allow you to go to any VC
The second solution is something like this.
Here You will show the last VC and from there push some VC.
guard let tabCount = viewControllers?.count, tabCount > 1 else { return }
selectedIndex = tabCount - 1
if let navigationController = viewControllers?[selectedIndex] as? UINavigationController {
if let accountVC = navigationController.visibleViewController as? FirstViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let vc = storyboard.instantiateViewController(withIdentifier: "someViewController") as? SomeViewController else { return }
accountVC.navigationController?.pushViewController(vc, animated: true)
}
}
I'm trying to want to present/push a VC embedded in a NavController from AppDelegate. I previously used this code but somehow it's not working anymore:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let VC = storyboard.instantiateViewControllerWithIdentifier("PendingRequest") as! PendingRequestVC
let navController = UINavigationController.self(rootViewController: VC)
let rootViewController = UIApplication.sharedApplication().keyWindow!.rootViewController
rootViewController!.presentViewController(navController, animated: false, completion: nil)
Other codes open my desired VC but not within a navigation pane. Any guidance would be appreciated.
Calling from AppDelegate after user interacts with push notification.
Edit:
I'm able to present the right VC by using this code:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let viewController = mainStoryboard.instantiateViewControllerWithIdentifier("PendingNavController") as? UINavigationController {
if let yourViewController = viewController.topViewController as? PendingRequestVC {
//yourViewController.getRequestdata()
}
UIApplication.sharedApplication().keyWindow!.rootViewController = viewController;
}
But this code won't allow me to go back using the Close button on my NavBar.
My structure is as follow:
TabController -> NavController1 -> VC1 -> NavController1a -> VC1a
I'm trying to get to VC1a and be able to use the Closed button to go back to VC1
Add a UIButton in your presented ViewController's View. Following event will be performed by that button. You can dismiss your Navigation Controller this way
#IBAction func dismissViewController(sender: AnyObject) {
self.navigationController.dismissViewControllerAnimated(false, completion:nil);
}
I have the following ViewController structure, see image below.
Whenever I want to move from ViewController 1 to any of the other main controllers I use self.tabBarController?.selectedIndex = indexNumber
// for instance, this would take me to ViewController 3
self.tabBarController?.selectedIndex = 2
Based on the picture below, how can I go from ViewController 1 to TargetViewController programmatically when a button is tapped in ViewController 1?
FYI -
In the picture below I'm showing a button in ViewController 3 this is just to show the storyboard structure, the actual button-tap will happen in ViewController 1
EDIT:
Here is how you do it based on Prashant Tukadiya's answer.
ViewController 1
In ViewController 1 add the following in your tap event.
self.tabBarController?.selectedIndex = 2
let nav = (self.tabBarController?.viewControllers?[2] as? UINavigationController)
let vc = TargetViewController.viewController()
nav?.pushViewController(vc, animated: true)
TargetViewController
In your TargetViewController add the following class method.
class func viewController() -> TargetViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "targetViewControllerID") as! TargetViewController
}
Add targetViewControllerID in the Storyboard ID field.
I was facing same before a couple of days and finally, I got a solution maybe this will help you.
TabController.shared.tabcontroller.selectedIndex = 1
let navigation = TabController.shared.tabcontroller.selectedViewController?.navigationController
let SavedAddress = self.storyboard?.instantiateViewController(withIdentifier: "SavedAddressVC") as! SavedAddressVC
navigation?.pushViewController(SavedAddress, animated: true)
I have used the same solution. and this is the working code for me.
You can directly give identifier to the TargetViewController from storyboard and load from storyboard then and push or present it.
like add this method in your TargetViewController
class func viewController () -> TargetViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewController(withIdentifier: "yourIdentifer") as! TargetViewController
}
and on tap event
let vc = TargetViewController.viewController()
self.navigationController?.pushViewController(vc, animated: true)
EDIT
After reading comments got clear idea about your requirements
On button action from ViewController1, You want to goto TargetViewController but when press back you want back to viewController 3
Select particular index first
self.tabBarController?.selectedIndex = 2
After that you need to grab UINavigationController
let nav = (self.tabBarController?.viewControllers?[2] as? UINavigationController)
then Push ViewController
let vc = TargetViewController.viewController()
nav?.pushViewController(vc, animated: true)
Note: Don't forgot add identifier to storyboard to TargetViewController and also add class func viewController () -> TargetViewController method to TargetViewController
Hope it is helpful
In action function of a button in ViewController 1 , you can use this :
func presentMethod(storyBoardName: String, storyBoardID: String) {
let storyBoard: UIStoryboard = UIStoryboard(name: storyBoardName, bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: storyBoardID)
self.definesPresentationContext = true
self.present(newViewController, animated: true, completion: nil)
}
//usage
presentMethod(storyBoardName: "Main", storyBoardID: "TargetViewController")