Add viewcontroller to navigation controller programmatically then push another view controller - ios

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.

Related

How to present a ViewController with a Navigationbar programatically?

When presenting my viewcontroller this way I don't get a navigationbar, even though the viewcontroller is embedded in a navigation controller in the interface builder.
if let stockVC = storyboard?.instantiateViewController(withIdentifier: "Stock") as? StockTableViewController {
stockVC.stockToDisplay = commonData.stock.filter { $0.productID.contains(product) }
// No NavigationBar with this one
navigationController?.present(stockVC, animated: true)
// No NavigationBar with this one
self.present(stockVC, animated: true)
}
I know the navigationBar works, because if I set the ViewController as initial in the storyboard, it shows.
What am I doing wrong here?
When you present a view controller, it is not part of the current navigation stack. You need to create a new navigation controller with your stockVC contained in it, and present the new navigation controller:
if let stockVC = storyboard?.instantiateViewController(withIdentifier: "Stock") as? StockTableViewController {
stockVC.stockToDisplay = commonData.stock.filter { $0.productID.contains(product) }
let stockNavigationController = UINavigationController(rootViewController: stockVC)
self.present(stockNavigationController, animated: true)
}

Make the navigation bar show the required title

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)

Open specific View Controller in swift

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]
}

navigation through view controllers while skipping one - iOS

I have a view controller as my initial view controller.
there's a button in it(GO button) which when the user taps, it should go to another view controller(let's call it Destination view controller with label 'This is where i wanna go'). Meanwhile i want to pass it through a Tabbar controller. The reason is i want to have tabbar in my navigation stack and when users presses back on Destination view controller, it must go to tabbar controller. Picture shows what i want. what can I do to skip tabbar while having it in navigation stack?
You can do that easily inside the IBAction of GO button:
#IBAction func goTapped(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc1 = storyboard.instantiateViewController(withIdentifier: "myTabBarViewController")
let vc2 = storyboard.instantiateViewController(withIdentifier: "myGoalViewController")
let controllers = [vc1, vc2]
self.navigationController!.setViewControllers(self.navigationController!.viewControllers + controllers, animated: true)
}
Good luck!
Going to DestinationViewController could be manually:
if let destinationViewController = self.storyboard?.instantiateViewController(withIdentifier: "Storyboard ID of DestinationViewController") {
self.navigationController?.pushViewController(destinationViewController, animated: true)
}
(Alternatively, you could make a segue from FirstViewController to the DestinationViewController directly in Storyboard)
And in your DestinationViewController, insert the TabbarController to the Navigation sequence manually after view did appear, then you are able to go back to the TabbarController:
class DestinationViewController: UIViewController {
//......
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if self.isBeingPresented || self.isMovingToParentViewController {
var viewControllers = self.navigationController?.viewControllers
if let index = viewControllers?.endIndex.advanced(by: -1),
let tabBarController = self.storyboard?.instantiateViewController(withIdentifier: "Storyboard ID of TabBarController") {
viewControllers?.insert(tabBarController, at: index)
self.navigationController?.viewControllers = viewControllers!
}
}
}
//......
}

Swift ios reset viewcontroller hierarchy

In storyboard my app is designed as:
Navigation VC -> VC1
What I am trying to do is to segue to another VC but reset the menu-hierarchy so that i dont have the old VC's stacked in the backgound
What I want to do is:
Navigation VC -> VC1 -> VC2 -> NEW VC with Navigation reseted
So when a user logs in and enters the account VC/Page the navigation stack should be resetted when hitting the account VC/Page
Is this possible to do?
If you do not want to add the view controllers to your navigation controller, every View controller you navigate to you can set that as the root view controller of your navigation controller and it won't be added in your stack.
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let yourViewController: ViewController = storyboard.instantiateViewControllerWithIdentifier("respectiveIdentifier") as! ViewController
let navigationController = self.view.window?.rootViewController as! UINavigationController
navigationController.setViewControllers([yourViewController], animated: true)
My solution same as above but one line less
let yourViewControllerObejct = self.storyboard?.instantiateViewControllerWithIdentifier("YourViewControllerId") as? YourViewController
let navigationController = self.view.window?.rootViewController as! UINavigationController
navigationController.setViewControllers([yourViewControllerObejct!], animated: true)

Resources