Swift dismiss current Viewcontroller after presenting new ViewController - ios

My scenario, I am trying to create multiple present ViewController. Here, presenting new ViewController after I need to dismiss previous ViewController.
ViewController A (RootViewController) next button click to presenting ViewController B then View Controller B next button click to present ViewController C. Now, If I close ViewController C need to show ViewController A.

Here is how you can proceed,
class VCA: UIViewController {
#IBAction func onTapNextButton(_ sender: UIButton) {
if let controller = self.storyboard?.instantiateViewController(withIdentifier: "VCB") as? VCB {
self.present(controller, animated: true, completion: nil)
}
}
}
Since VCC is embedded in a UINavigationController, you need to present UINavigationController instead of VCC.
For this subclass UINavigationController and set it as class of UINavigationController in the storyboard.
class VCB: UIViewController {
#IBAction func onTapNextButton(_ sender: UIButton) {
if let controller = self.storyboard?.instantiateViewController(withIdentifier: "NavVC") {
self.dismiss(animated: false, completion: nil)
self.presentingViewController?.present(controller, animated: true, completion: nil)
}
}
}
class NavVC: UINavigationController {}
class VCC: UIViewController {
#IBAction func onTapCloseButton(_ sender: UIButton) {
self.navigationController?.dismiss(animated: true, completion: nil)
}
}

Related

How to correctly dismiss a modal View Controller?

Inside my Custom TabBarController I set the NavigationController for each tab
let viewController = [HomeViewController(), ProfileViewController()]
let navControllers = viewControllers.map { return UINavigationController(rootViewController: $0) }
setViewControllers(navControllers, animated: false)
In my HomeViewController I have a CollectionView that when selecting a cell it pushes my VideoPlayerViewController to the NavigationController. The VideoPlayerViewController then presents a ViewController as a modal:
class PopoverViewController: UIViewController {
#IBAction func presentPopover() {
let popoverViewController = PopoverViewController()
popoverViewController.modalPresentationStyle = .fullScreen
popoverViewController.delegate = self
present(popoverViewController, animated: true, completion: nil)
}
}
In my PopoverViewController I have a close button that calls the delegate method in the VideoPlayerViewController:
class PopoverViewController: UIViewController {
#objc func closeTapped() {
delegate?.willClose(self)
}
}
extension VideoPlayerViewController: PopoverViewControllerDelegate {
func willClose(_ viewController: PopoverViewController) {
viewController.dismiss(animated: true, completion: nil)
}
}
When calling dismiss on my PopoverViewController it not only dismisses the modal ViewController but it also pops the VideoPlayerViewController from the NavigationController and it returns to the rootViewController (HomeViewController).
I want to go back to the VideoPlayerViewController and only dismiss the PopoverViewController without popping the VideoPlayerViewController.
You are calling the dismiss on your VideoPlayerViewController. This should be done on the PopoverViewController as below:
class PopoverViewController: UIViewController {
#objc func closeTapped() {
dismiss(animated: true, completion: nil)
}
}

How to dismiss previous Viewcontroller after presenting new Viewcontroller using Swift?

My Scenario, In my project I am maintaining three ViewController (Main, VC1 and VC2). In main ViewController I am maintaining UIButton, This button click to VC1 presenting model view controller. Again, VC1 I am maintain UIButton with action click to present model to VC2. After VC2 presenting I need to dismiss VC1.
// presenting ViewController
var presentingViewController: UIViewController! = self.presentingViewController
self.dismissViewControllerAnimated(false) {
// go back to MainMenuView as the eyes of the user
presentingViewController.dismissViewControllerAnimated(false, completion: nil)
}
Try this in VC2's close button action
var vc = self.navigationController?.presentingViewController
while vc?.presentingViewController != nil {
vc = vc?.presentingViewController
}
vc?.dismiss(animated: true, completion: nil)
Hope this will work:
You need to have a UIViewController as a base, in this case MainViewController is the base ViewController. You need to use a protocol to call the navigation between Controllers.
you can do using protocol:-
In to your FirstViewController setting Protocol :
protocol FirstViewControllerProtocol {
func dismissViewController()
}
class FirstViewController: UIViewController {
var delegate:FirstViewControllerProtocol!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func goBack(sender: AnyObject) {
self.dismissViewControllerAnimated(true) {
self.delegate!.dismissViewController()
}
}
Now in your MainViewController
class MainViewController: UIViewController, FirstViewControllerProtocol {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func goToFirstViewController(sender: AnyObject) {
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(String(FirstViewController)) as! FirstViewController
viewController.delegate = self
self.presentViewController(viewController, animated: true, completion: nil)
}
//MARK: Protocol for dismiss
func dismissViewController() {
if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(String(SecondViewController)){
self.presentViewController(viewController, animated: true, completion: nil)
}
}
To solve the problem statement, what you can do is present VC2 using Main instead of VC1.
We can get the reference to Main in VC1 using
self.presentingViewController
When VC2 is presented, dismiss VC1 in the completionHandler of present(_:animated:completion:) method
class Main: UIViewController {
#IBAction func onTapButton(_ sender: UIButton) {
let vc1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "VC1")
self.present(vc1, animated: true, completion: nil)
}
}
class VC1: UIViewController {
#IBAction func onTapButton(_ sender: UIButton) {
let vc2 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "VC2")
vc2.view.backgroundColor = .blue
self.dismiss(animated: false, completion: nil)
self.presentingViewController?.present(vc2, animated: true, completion: nil)
}
}
class VC2: UIViewController {
}
This approach is giving the expected output. Let me in case anything else is required.
You need to open vc2 from the mainVC - In order to do this you need a delegate method which will tell mainVC to close the current opened vc (i.e. vc1) and in the success block open vc2.
Code Snipet:-
dismiss(animated: false) {
//Open vc2
present(vc2)
}
In this case you need to call dismiss from the view controller over which your other view controllers are presented(Main in your case).
As you stated your situation in the question above Main presents VC1 and VC1 then presents VC2:
then calling Main.dismiss(animated: true, completion: nil) will dismiss VC1 and VC2 simultaneously.
If you don't have a reference to the root controller(Main), you could chain a couple of presentingViewController properties to access it; Something like this in the topmost controller(VC2):
presentingViewController?.presentingViewController?.dismiss(animated: true)
I hope this helps.
There is a present(_:animated:completion:) method which takes a completion. Inside that you can dismiss your VC1.
Your code will look something like this
#IBAction func ButtonTapped(_ sender: Any) {
present(VC2, animated: true) {
dismiss(animated: true, completion: nil)
}
}

How to go from child UIViewController to parent UIViewController and from there to another child UIViewController

I have a parent UIViewController(MainVC). From there I have 2 segue to 2 UIViewControllers: FirstVC (identifier: goFirstVC) and SecondVC (identifier: goSecondVC)
In FirstVC I have a button Save and when I click it I want to dismiss the FirstVC and to go on SecondVC.
Here is my code:
#IBAction func saveBtnTapped(_ sender: UIButton) {
//navigationController?.popViewController(animated: true)
let destinationController = self.storyboard?.instantiateViewController(withIdentifier: "goSecondVC") as! SecondVC
let presentingVC = self.presentingViewController
self.dismiss(animated: false, completion: { () -> Void in
presentingVC!.present(destinationController, animated: true, completion: nil)
})
}
Here is the design for my issue:
You can use setViewControllers to keep the parent only and the SecondVC
let destinationController = self.storyboard?.instantiateViewController(withIdentifier: "goSecondVC") as! SecondVC
self.navigationController?.setViewControllers([self.navigationController!.viewControllers.first!,destinationController], animated: true)
There are many methods but one of the generic one is to use delegates and protocols. Use the following code in your classes.
Add Following code in the first VC
protocol SecondVCDelegate : AnyObject {
func goToSecondVC()
}
class FirstVC: UIViewController {
var Delegate : SecondVCDelegate!
#objc func save() {
Delegate.goToSecondVC()
}
}
//In second view
Add following code in MinVC
class MainVC: UIViewController {
override func viewDidAppear() {
self.performSegue(withIdentifier: <yourSegueIdentifierToFirstVC>, sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == <yourSegueIdentifierToFirstVC> {
let cont = segue.destination as! FirstVC
cont.Delegate = self
}
}
}
extension MainVC : SecondVCDelegate {
func goToSecondVC() {
self.performSegue(withIdentifier: <yourSegueIdentifierToSecondVC>, sender: nil)
}
}
//This is MainVC
I think you should present second from first rather than dismissing first then presenting second.
when you will present second from first then if you wanto go back to main you can simply dismiss 2 veiwcontrollers at once without any hack.
try it:
We can control our presented controllers with navigation controller calling pushViewController and popViewController methods.
FirstVC.navigationController?.popViewController(animated: animated) // pops the top view controller
self.navigationController?.pushViewController(SecondVC, animated: true) // Pushes a view controller onto navigation's stack of controllers
In your case:
let destinationController = self.storyboard?.instantiateViewController(withIdentifier: "goSecondVC") as? SecondVC
self.navigationController?.popViewController(animated: animated)
self.navigationController?.pushViewController(destinationController, animated: true)

how can I dismiss first vc that second has presented modally on the first vc

I have a view controller that named "firstVC" and another one that named "secondVC" . the secondVC will present modally on the first vc I want to dismiss firstVC and secondVC when user push the button on the secondVC
I call the method here But it does execute But nothing will happen
in the secondVC this will happen
firstVC.dismiss(animated: true, completion: nil)
if you suggest me to use delegate please tell me how can I use that completely ? I don't know what should I put in the firstVC or what should I put in the secondVC
one more thing
In some other cases I need to execute json in the firstVC and when json has complete the both view controllers (firstVC and secondVC) be dismiss how can I do that too ?
Here is a solution using delegate:
protocol DismissDelegate{
func dismissVC()
}
class FirstViewController: UIViewController, DismissDelegate{
func showSecondVC(){
let secondVC = SecondViewController()
secondVC.delegate = self
}
func dismissVC(){
self.dismiss(animated: true, completion: nil)
}
}
class SecondViewController: UIViewController{
var delegate: DismissDelegate?
#IBAction func buttonAction(sender: UIButton){
self.dismiss(animated: true, completion: nil)
delegate?.dismissVC()
}
}

How to present another view controller after dismiss from navigation controller in swift?

How to present another view controller after dismiss from navigation controller in swift ?
I am using Navigation controller.
ViewController1.swift
func pushTo(viewController: UIViewController) {
let showLocalPwd = self.storyboard?.instantiateViewController(withIdentifier: "LocalPwdVC") as! LocalPwdVC
self.navigationController?.present(showLocalPwd, animated: true, completion: nil)
}
ViewController2.swift
#IBAction func btnVerify(_ sender: Any)
{
self.dismiss(animated: true, completion: {
let vc = self.storyboard.instantiateViewController(withIdentifier: "DataVC") as! DataVC
self.navigationController.pushViewController(vc, animated: true)
})
}
After dismissing the View Controller, it will not goes to next viewcontroller i.e. DataVC
If you want to present the view controller then create a protocol in your dismissViewController
protocol dismissViewController {
func presentCompletedViewController()
}
// Then create a delegate
var delegate = dismissViewController? = nil
// If you are using action to dismiss your ViewController then call delegate
#IBAction func YourButton(_ sender: Any) {
self.dismiss(animated: true) {
self.delegate!.presentCompletedViewController()
}
}
//And then call this in your main or homeViewController
class HomeViewController: UIViewController, dismissViewController {
func presentCompletedViewController(){
// enter code to present view controller
}
// And at last don't forget to call delegate
yourVc.delegate = self
you need to call this delegate in which you are presenting your dismissViewController

Resources