etnclp
etnclp

Reputation: 572

How to replace ViewController in Swift?

I have presented ViewController1 using this code:

let vc1 = ViewController1()
present(vc1, animated: true, completion: nil)

Now, I want to show ViewController2 in ViewController1.

@IBAction func buttonEvent(_ sender: UIButton) {
    let vc2 = ViewController2()
    self.present(vc2, animated: true, completion: nil)
}

The problem is: I want to show the ViewContoller2 while the current ViewController is being dismissed when the button event is called.

And I want to animation while doing this.

Thank you.

Upvotes: 19

Views: 26315

Answers (5)

Michael N
Michael N

Reputation: 563

If your app uses AppDelegate, SceneDelegate and Storyboard, assign an identifier to the ViewController you wish to replace the current vc with

// replace viewController

let storyboard = UIStoryboard.init(name: "Main", bundle: nil)

let destinationViewController = storyboard.instantiateViewController(identifier: "MyViewControllerIdentifier")

UIApplication.shared.windows.first!.rootViewController = destinationViewController

Upvotes: 2

Vikram Biwal
Vikram Biwal

Reputation: 2826

var viewControllers = self.navigationController?.viewControllers
viewControllers[viewControllers.count - 1] = newViewController
self.navigationController?.setViewControllers(viewControllers!, animated: true)

Upvotes: 2

CDM
CDM

Reputation: 517

You can create a function in SceneDelegate, modify the root view controller and access it with (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.yourFunctionHere(view: UIViewController). unless your app doesnt use a navigation controller or a tab view you can probly just use a presetSegue() function.

https://fluffy.es/how-to-transition-from-login-screen-to-tab-bar-controller/

Upvotes: 0

Dorukhan Arslan
Dorukhan Arslan

Reputation: 2754

You may achieve this through navigationController as follows:

guard var viewControllers = sourceViewController.navigationController?.viewControllers else { return }

// Popped ViewController not used
_ = viewControllers.popLast()

// Push targetViewController
viewControllers.append(targetViewController)

sourceViewController.navigationController?.setViewControllers(viewControllers, animated: true)

Get viewControllers in your navigation stack at first. Pop the current and append the target one. Then, set your stack to updated viewControllers.

Additions

(For those who do not use navigationController)

I realized a possible problem in the given answer. Thus I want to make this addition. Check documentation of parent before continue. I want to lay emphasis on this part:

If the recipient is a child of a container view controller, this property holds the view controller it is contained in. If the recipient has no parent, the value in this property is nil. Prior to iOS 5.0, if a view did not have a parent view controller and was being presented, the presenting view controller would be returned. On iOS 5, this behavior no longer occurs. Instead, use the presentingViewController property to access the presenting view controller.

In brief, if you want to dismiss the current UIViewController (sourceViewController) and present the next one (targetViewController), you should make the present() call from presentingViewController of the current.

weak var presentingViewController = self.presentingViewController

sourceViewController.dismiss(animated: true, completion: {
    presentingViewController?.present(targetViewController, animated: false, completion: nil)
})

Though you probably see the transition this time, at the end of the completion of sourceViewController's dismiss(), the presentingViewController will be shown till the targetViewController is presented. I don't know whether you expect this behavior. If no, I couldn't come up with a workaround to prevent this for now.

Upvotes: 30

Hosein Safaei
Hosein Safaei

Reputation: 61

this worked for me

viewControllers = self.navigationController?.viewControllers
viewControllers.remove(at: viewControllers.count - 1)
self.navigationController?.setViewControllers(viewControllers, animated: true)
self.performSegue(withIdentifier: "destinationVC", sender: self)

Upvotes: 6

Related Questions