I have 3 view controllers: VC1 -> VC3 -> VC2. Transit from VC3 to VC2 I made by next code:
let storyboard = UIStoryboard(name: "VCs", bundle: nil)
let myVC2 = storyboard.instantiateViewController(withIdentifier: "VC2") as? VC2
myVC2?.name = "Test"
self.navigationController?.pushViewController(myVC2!, animated: true)
In viewDidLoad() of VC2 I delete VC3 from viewControllers stack and left only VC1:
var navigationVCs = self.navigationController?.viewControllers
navigationVCs!.remove(at: 1)
self.navigationController?.viewControllers = navigationVCs!
All work well. But I have one visual "Issue". When the view controller moves from VC4 to VC3, and VC3 view starts a load, NavigationBar back button of VC3 first of all show title of VC4, and only then switches to VC1 title. How I can fix this and force VC2 show back button title of VC1? Thanks.
You can pass through the back button title of VC1 to VC2 in the VC3 this way:
if let navigationController = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController {
if let previousVC = navigationController.viewControllers.first {
let backItem = UIBarButtonItem()
let title = previousVC.navigationItem.backBarButtonItem?.title
backItem.title = title
navigationItem.backBarButtonItem = backItem // This will show in the next view controller being pushed
}
}
before you call
self.navigationController?.pushViewController(myVC2!, animated: true)
Related
I want to append couple of viewcontrollers in array of viewcontroller of a navigation controller, then want push third viewcontroller of the same navigation controller.
My code is as follows
let navigationController = getCurrentNavController()
let listVC = UIStoryboard.loadListViewController()
navigationController.viewControllers.append(listVC)
let detailVC = UIStoryboard.loadDetailsViewController()
navigationController.viewControllers.append(detailVC)
let thirdVC = UIStoryboard.loadThird()
navigationController.pushViewController(thirdVC, animated: true)
The thirdVC is push on the navigation controller,
the problem is when i pop thirdVC,
I don't find detailVC or listVC.
Is this possible?
if yes please help.
Don't edit the viewControllers array directly. That is why the animated parameter exists.
A solution may be to add the viewControllers in between after 0.25 seconds (the duration of the push animation) by doing:
let navigationController = getCurrentNavController()
var viewControllers = navigationController.viewControllers
let listVC = UIStoryboard.loadListViewController()
viewControllers.append(listVC)
let detailVC = UIStoryboard.loadDetailsViewController()
viewControllers.append(detailVC)
let thirdVC = UIStoryboard.loadThird()
viewControllers.append(thirdVC)
navigationController.pushViewController(thirdVC, animated: true)
DispatchQueue.main.asyncAfter(now() + 0.25) {
navigationController.setViewControllers(viewControllers, animated: false)
}
As mentioned, you do not want to modify the navigation controller's viewControllers directly.
But, you also don't need to do any explicit "pushing":
let navigationController = getCurrentNavController()
let listVC = UIStoryboard.loadListViewController()
let detailVC = UIStoryboard.loadDetailsViewController()
let thirdVC = UIStoryboard.loadThird()
var vcs = navigationController.viewControllers
vcs.append(listVC)
vcs.append(detailVC)
vcs.append(thirdVC)
navigationController.setViewControllers(viewControllers, animated: true)
This will animate thirdVC in from the current view controller, just as if you had pushed it, but it will also insert listVC and detailVC into the navigation controller's stack so the "Back" button will take you through detailVC and listVC.
I am having a problem when performing segue from my AppDelegate. I am using this code to do a segue from appdelagate:
let storyboard = UIStoryboard(name: "MyStoryboard", bundle: nil)
let viewController: MyViewController = storyboard.instantiateViewController(withIdentifier: "myviewcontroller") as! MyViewController
let rootViewController = self.window!.rootViewController as! UINavigationController
rootViewController.show(viewController, sender: self)
When I use this, my UITabBar is removed. I want to segue to a ViewController that is not a TabBar item and retain my UITabbar. I am also using navigation. How should I approach this?
To show the tab , you need to do the push from 1 of the tab vcs , and it should be embeded inside a navigation and use
let nav = self.window!.rootViewController as! UINavigationController
if let tab = nav.viewControllers.first as? UITabBarController ,
let innerNav = tab.viewControllers.first as? UINavigationController {
innerNav.pushViewController(viewController,animated:true)
}
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've asked a question before and it works successfully thanks to the one of the answers How to instantiate a navigation controller from another view controller?, but I have come across a new problem which is , whenever i click a button from a show detail segue, it supposed to navigate to a normal tab with a navigation bar, but it did nothing.
Here's the storyboard
Here's the scenario
1) User click on a button on a firstViewController and it will segue to a thirdViewController which is in show detail
2) User click another button which will then supposed to go to a secondViewController with the codes below
Here's the code
in ThirdViewController
#IBAction func buttonTapped(sender: UIButton) {
guard let tabBarController = tabBarController else { return }
let navController = tabBarController.viewControllers![1] as! UINavigationController
let secondViewController = navController.topViewController as! SecondViewController
secondViewController.name = "My name is TDog"
tabBarController.selectedIndex = 1
}
What did i do wrong? Do i still need to instantiate?
You have to dismiss the actual ThirdViewController but, in this class, you dont know yet UITabViewController so a way to obtain it ( not to re-instantiate but to recall from memory) is to call the rootViewController of your window (it can be done in your project):
#IBAction func buttonTapped(sender: AnyObject) {
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let tabBarController = appDelegate.window!.rootViewController
if tabBarController is UITabBarController {
let tab = tabBarController as! UITabBarController
let navController = tab.viewControllers![1] as! UINavigationController
let secondViewController = navController.topViewController as! SecondViewController
secondViewController.nameString = "My name is TDog"
tab.selectedIndex = 1
}
}
You got to call
self.presentingViewController.dismissViewControllerAnimated(true, completion: nil)
after the following line
tabBarController.selectedIndex = 1