navigation through view controllers while skipping one - iOS - 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!
}
}
}
//......
}

Related

Can I preserve a modally presented view controller when setting the root view controller?

Let's say I have three view controllers. On the first one, I tap a button and present the second view controller modally. On the second one, I tap a button and store the presenting view controller (first), then set the third view controller as the root view controller. Finally, I have a button on the third view controller that grabs the stored controller and sets that as the root view controller.
When I restore the first view controller, I find that its presentedViewController property is nil. I wonder if I can preserve the navigation stack and have the modal presented when I restore the first view controller?
In this example I'm storing the view controller inside AppDelegate for simplicity.
Code:
FirstViewController.swift
#IBAction func presentViewController(_ sender: Any) {
let storyboard = UIStoryboard(name: "SecondVC", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "Second")
present(controller, animated: true, completion: nil)
}
SecondViewController.swift
#IBAction func secondButtonCLick(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.savedVC = presentingViewController
let storyboard = UIStoryboard(name: "Third", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ThirdVC")
UIApplication.shared.keyWindow?.rootViewController = controller
}
ThirdViewController.swift
#IBAction func thirdBtnTouch(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let rootVC = appDelegate.savedVC
UIApplication.shared.keyWindow?.rootViewController = rootVC
}

View Controllers not being presented correctly

When the function is done executing I want to go back to my ProfileTabViewController. I want to get sent back to the view controller keeping the ProfileTabViewControllers same navigation bar and UITabBarController from before. The way I have it now it gets sent to the ProfileTavViewController but I lose my navigation bar as well as the tab bar. How do I just send it back to the original ProfileTabViewController. The first image is the original ViewController and the second image is when it gets sent back.
#IBAction func updateAction(_ sender: Any) {
let newInterests = options.joined(separator: " , ")
if newInterests == ""{
showAlert(message: "Please select at least one interest.")
}else{
updateFunction()
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ProfileTabViewController") as! UIViewController
self.navigationController?.present(vc, animated: true, completion: nil)
}
}
While Presenting a ViewController it will not show navigationbar beacause presentation depends on UIViewController not NavigationViewcontroller.
You have to use popViewController method to get navigation bar.
for controller in self.navigationController?.viewControllers {
if controller is ProfileViewController {
self.navigationController!.popToViewController(controller, animated: true)
break
}
}
//Use Pop

How to go back to the initial ViewController the right way?

I have a few view controllers with navigation bar and tab bar. Then I have an initial view controller with no navigation bar and tab bar. I want to go back to the initial view controller with no other view controllers in stack. Here's what I do:
// Head back to Initial View Controller.
let initialViewController = self.storyboard!.instantiateViewController(withIdentifier: "Initial")
UIApplication.shared.keyWindow?.rootViewController = initialViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = initialViewController
This works perfectly. But then it doesn't move to another view controller from the initial view controller again. For example:
#IBAction func loginButton(_ sender: Any) {
print("Login Button Tapped.")
let storyboard = UIStoryboard(name: "SignInViewController", bundle: nil)
let signInViewController = storyboard.instantiateViewController(withIdentifier: "SignInViewController") as! SignInViewController
self.navigationController?.show(signInViewController, sender: nil)
}
Here, the print statement is run, but self.navigationController.show won't. How do all this work? And what's the right approach to accomplish this?
EDIT:
To avoid any confusion, here's my storyboard. The left most viewcontroller (pink screen) is the initial view controller I want to go back to. The right most on the same level is the view where I want to go back from.
It doesn't move to another view controller, because you are setting a simple view controller in your rootViewController.
What you need is:
let initialViewController = self.storyboard!.instantiateViewController(withIdentifier: "Initial")
let navController = UINavigationController.init(rootViewController: initialViewController)
UIApplication.shared.keyWindow?.rootViewController?.present(navController, animated: true, completion: nil)
This will create a navigationviewcontroller, so when on "Initial" you should be able to perform push, present actions of another view controllers.
From your initial view controller, you need to instantiate your navigation stack and present it modally. Then, when you want to get back to your pre-navigation initial VC, just call dismiss(animated:,completion:), which will dismiss your entire navigation stack and return you to the initial view controller.
self.navigationController.popToRootViewController(animated:) is what you're looking for.
https://developer.apple.com/documentation/uikit/uinavigationcontroller/1621855-poptorootviewcontroller
EDIT
Try dismissing the navigationController after calling popToRoot.
self.navigationController.dismiss(animated: true, completion: nil)
EDIT
Try the following:
#IBAction func loginButton(_ sender: Any) {
print("Login Button Tapped.")
let storyboard = UIStoryboard(name: "SignInViewController", bundle: nil)
let signInViewController = storyboard.instantiateViewController(withIdentifier: "SignInViewController") as! SignInViewController
present(signInViewController, animated: true, completion: nil)
//self.navigationController?.show(signInViewController, sender: nil)
}
Then to dismiss the signInViewController call self?.navigationController.dismiss(animated:true, completion:nil) from inside the signInViewController.

How to instantiate a navigation controller from another view controller?

My goal is whenever i click a button on a first view controller, then it will navigate to another controller which is a navigation controller.
firstViewController and secondViewController has no connection or anything.
Picture
I used this code
#IBAction func buttonTapped(sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("secondViewCtrl") as! SecondViewController
self.presentViewController(vc, animated: true, completion: nil)
}
The reason why i instatiate so that I could pass data like
vc.name = "Myname"
The problem with this code is that it doesn't present navigation bar and as well as the tab bar. What should I do to show both?
Updated question
#IBAction func buttonTapped(sender: UIButton) {
guard let tabBarController = tabBarController else { return }
tabBarController.selectedIndex = 1
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("trackYourGenie") as! TrackYourGenieViewController
let navController = tabBarController.viewControllers![1]
let secondViewController = navController.topViewController
vc.name = "Myname"
}
You are instantiating the view controller hence you wouldn't get the navigation bar. To get the navigation bar please instantiate navigation controller and since the second view is only child you would get the second view by default.
#IBAction func buttonTapped(sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("Navigation Controller Id") as! UINavigationController
self.presentViewController(vc, animated: true, completion: nil)
}
The above code should give you the navigation bar.
A safe approach:
guard let tabBarController = tabBarController else { return }
tabBarController.selectedIndex = 1
If you need to access to your tabBarController to pass datas you can do simply:
let navController = tabBarController.viewControllers[1]! as! UINavigationController
let secondViewController = navController.topViewController
Your method could be:
#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"
tabBarController.selectedIndex = 1
}
In your case, the following code should be sufficient :
self.tabBarController.selectedIndex = 1
As UITabBarController is your rootViewController, you can access it with self.tabBarController. You don't have to instantiate UINavigationController as it is in the storyboard.
I can see from your StoryBoard that you have a TabBarController. If your configuration is that and FirstViewController is on first tab and SecondViewController on second tab, you can just change TabBarController selectedIndex property:
#IBAction func buttonTapped(sender: UIButton) {
tabBarController?.selectedIndex = 1
}
If you want to pass data to SecondViewController you can try one of these solutions:
let controller = tabBarController.viewControllers[1] as SecondViewController!
controller.data = "some data"
This soultion could not work since SecondViewController is not ready yet.
Create a singleton class where to save data, then retrieve data in SecondViewController viewDidLoad method
Save data in UserDefaults, then retrieve data in SecondViewController viewDidLoad method (bad solution if information doesn't have to be persistent)
Extend UITabBarController and use it, create a custom var in tabBarController, put data in that variable and then retrieve data in SecondViewController viewDidLoad method
Then clear data if needed.
Navigation will not work from firstViewController as to navigate something we need UINavigationController.
Try Like This

Swift Xcode Button not showing next view

I'm trying to code a button that simply switches to the next view. So I embedded the first ViewController into a navigation controller then I dragged in another view controller, created a new class name ViewController2 and associated that class with the second ViewController and came the second view controller a storyboard id:"view2". Then in the Button's function I added this code:
#IBAction func newGamePressed(sender: AnyObject) {
let view2 = self.storyboard?.instantiateViewControllerWithIdentifier("view2") as
ViewController2
self.navigationController?.pushViewController(view2, animated: true)
}
However when i click on the button, literally nothing happens!!! what am i doing wrong???
#IBAction func newGamePressed(sender: AnyObject) {
let VC1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("view2")
let navController = UINavigationController(rootViewController: VC1)
self.presentViewController(navController, animated:true, completion: nil)
}
Just try with this code.

Resources