Dismissing View Controller Doesn't Work While Using Navigation Controller - ios

I have two view controllers.
The first one is embedded in a Navigation Controller.
On the first view controller there is Bar Button Item which is connected by a segue to the second view controller. The segue is set as Push. Once I go to the second view controller there is a Bar Button Item which is an IBAction and should dismiss the page, but it doesn't.
Second View Controller Code:
import UIKit
class Page2ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func donePressed(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
}

Within your donePressed(_:) function, access the navigation controller and call the popViewController(_:) function.
#IBAction func donePressed(_ sender: Any) {
navigationController?.popViewController(animated: true)
}

Related

Add Tab Bar Programmatically to ViewController

I have a TabBarController in my Main.storyboard file.
In my Upload.storyboard I am presenting a ViewController from the Main.storyboard file, however, it doesn't contain the tab bar.
The viewProfile button should go to a tab called Sharks and within that present a view controller based on data gathered in the Upload.storyboard (modal view).
Can I add the tab bar programmatically or am I not properly presenting the correct VC?
// MARK: - Actions
#IBAction func viewProfileButtonPressed(_ sender: UIButton) {
let stb = UIStoryboard(name: "Main", bundle: nil)
let sharkProfile = stb.instantiateViewController(withIdentifier: "sharkProfile") as! SharkProfileTableViewController
self.present(sharkProfile, animated: true) {
// add tab bar here?
}
}
What you need to do is present the tab bar view controller, not the view controller that is embedded in it
One method is to create a Delegate Protocol to allow a tap on View Profile button to "call back" to the View Controller that presented it. When that callback is received, the VC sets the "current" tab.
It will look something like this:
// define "call back" delegate protocol
protocol EncounterUploadedDelegate : class {
func didTapSharkProfileButton()
}
The Encounter view controller will need to conform to that protocol:
class EncounterViewController: UIViewController, EncounterUploadedDelegate {
// the normal stuff for this VC and all the other code for it
// ...
// conform to the protocol
func didTapSharkProfileButton() -> Void {
// when we get this call-back, switch to the Shark Profile tab
// tabs are zero-based, so assuming "SharkProfile" is
// is the 4th tab...
self.tabBarController?.selectedIndex = 3
}
// assuming a "Show Modal" segue named "ShowEncounterUploadSegue" is used
// to present the Modal View
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "ShowEncounterUploadSegue" {
let vc = segue.destination as! TabModalVC
vc.encounterDelegate = self
}
}
}
The view controller to be presented as modal:
class TabModalVC: UIViewController {
weak var encounterDelegate: EncounterUploadedDelegate?
#IBAction func profileButtonTapped(_ sender: Any) {
// dismiss self (the modal view)
self.dismiss(animated: true, completion: nil)
// this will call back to the delegate, if one has been assigned
encounterDelegate?.didTapSharkProfileButton()
}
}
Hope that all makes sense :)

how to make a unwindsegue to viewcontroller before a navigation controller

i have a project where initial viewcontroller does not have a navigation controller a loguin windows after that i have a navigatino controller to the main view. so when I tap on close session i make a segue to loguin windows but that does not destroy any windows opened in previous, so I google for a solution an i show a unwindsegue to main viewviewcontroller but always the initial view controller is behind a navigation controller so my real question is is a valid approach to make
#IBAction func unwindToVC1(segue:UIStoryboardSegue) {
self.performSegue(withIdentifier: "goLogin", sender: nil)
}
You need change sender value nil to self value:
#IBAction func unwindToVC1(segue:UIStoryboardSegue) {
self.performSegue(withIdentifier: "goLogin", sender: self)
}

Dismiss View controller underneath current visible view controller in stack

How would I go about dismissing a view controller once a segue has been performed? Once the new view controller has animated on top, I want to dismiss the view controller underneath (the one which the segue was initially triggered from).
I tried the following code but I am getting issues with views not being in the heirarchy.
#IBAction func gotoSection1(_ sender: AnyObject) {
let presentingViewController: UIViewController! = self.presentingViewController
self.dismiss(animated: false) {
presentingViewController.dismiss(animated: false, completion: nil)
}
}
Any help would be greatly apprceiated.
Try this:
Add the below code to first view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
self.dismiss(animated: true, completion: nil)
}
It will dismiss the first view controller before presenting second view controller on top of it.
Edit:
Follow these steps and check:
Create a button in 1st View controller
Connect button to 2nd View controller with modal segue
Implement prepareForSegue in 1st view controller
Refer to these links:
Navigation Controller
https://developer.apple.com/reference/uikit/uinavigationcontroller
Presenting a controller
https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PresentingaViewController.html#//apple_ref/doc/uid/TP40007457-CH14-SW1

Returning to a view in a Tab Bar Controller Programatically

I have a TabBarController with 5 ViewControllers within it, on one of the ViewControllers, I have a set of buttons which load different view controllers outside of the TabBarController. These are loaded though the Modal Segue's, however the issue I am having is when I try to go back to the View within the Tab Bar it loads but without the Tab Bar itself, the code I have is:
class GreetingsVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func goBack(sender: AnyObject) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("anonScreen") as! AnonVC
self.presentViewController(nextViewController, animated:true, completion:nil)
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
How can I make it so when the back button is pressed it presents the View Controller from the Tab Bar Controller?
From my understanding, from the tabbar controller, you have present the GreetingsVC using presentViewController and you want to go back to previous view (one of the tabbar view controllers)
Instead of using presentViewController, you need to use dismissViewControllerAnimated
#IBAction func goBack(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}

is there a way of dismissing two uiViewControllers at the same time in Swift?

In my swift app I have a UIViewController with a button. This button opens up the UIViewController number 2 and there user has another button. When user presses it - he opens UIViewController number 3. There is also a button and when user presses it - he calls the code:
self.dismissViewControllerAnimated(false, completion: nil)
and thanks to it the UIViewController number 3 disappears and user sees UIViewController number 2. My question is - is there a way of also dismissing the UIViewController number 2 so that user can come back smoothly from number 3 to number 1?
For now I created a function and call it through protocol:
UIViewController number 2:
protocol HandleYourFullRequest: class {
func hideContainer()
}
class FullRequest: UIViewController, HandleYourFullRequest{
func hideContainer(){
self.dismissViewControllerAnimated(false, completion: nil)
}
#IBAction func exitbuttonaction(sender: AnyObject) {
self.performSegueWithIdentifier("temporarySegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "temporarySegue"){
if let fullRequestDetails = segue.destinationViewController as? YourFullRequest
{
fullRequestDetails.delegateRequest = self
}
}
}
}
UIViewController number 3:
class YourFullRequest: UIViewController{
var delegateRequest:HandleYourFullRequest?
#IBAction func exitbuttonaction(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
delegateRequest?.hideContainer()
}
}
But with that solution when user presses the button - the UIViewController number 3 disappears and UIViewController number 2 appears for a second and disappears then. Is there a way of removing number 2 without showing it to the user and point him directly to the number 1?
I'm still unclear as two which button is wired to which action, but from what I can tell when the dismiss button is pressed on view controller 3 it calls self.dismissViewControllerAnimated(false, completion: nil) in view controller number 2.
Try putting this method in view controller 3.
#IBAction func exitButtonAction(sender: AnyObject) {
self.presentingViewController?.presentingViewController?.dismissViewControllerAnimated(true, completion: nil);
}
This will work assuming that both view controllers are presented and not pushed in something like a navigation controller.
You can use removeLast() function to pop controllers off the stack.
#IBAction func doneAction(sender: AnyObject) {
var vc = self.navigationController?.viewControllers
// remove controllers from the stack
vc?.removeLast()
vc?.removeLast()
// Jump back to the controller you want.
self.navigationController?.setViewControllers(vc!, animated: false)
}
You can use popToViewController(viewController: UIViewController, animated: Bool)
Where viewController is the viewController you wish to pop to, in your case, 'UIViewController number 1'.
popToViewController Documentation
If you don't have a reference to the View Controller, you can get it from self.navigationController.viewControllers, it will be the first object in your example.
There is a method on UINavigationController called setViewControllers. It takes an array of all the view controllers you want active. You can get all the view controllers on the stack as an array, remove the ones you don't want, then call setViewControllers with the updated array.

Resources