How to dismiss view controller opened with present? - ios

Pretty new to Swift so forgive my ignorance. I have a navigation controller which is linked to a View controller called Profile. In ProfileViewController.swift I have it to where it opens up another view controller if no profile exists. Here's an example of what I have at the moment:
// ProfileViewController.swift
var profileExists = 0
override func viewDidLoad() {
super.viewDidLoad()
// Check if user has a profile. If so, go to view page; otherwise, bring up new profile view.
if profileExists != 1 {
// Create new profile page.
if let vc = storyboard?.instantiateViewController(withIdentifier: "EditProfileController") as? EditProfileViewController {
present(vc, animated: true, completion: nil)
}
print("Need to create new profile.")
}
//Scroll view size
ScrollView.contentSize.height = 1000
}
// Cancel button was pressed.
#IBAction func unwindToHomeScreen(segue:UIStoryboardSegue) {
}
What I'm trying to do is link my "Cancel" bar button in the "EditProfile" view controller to dismiss it if the user clicks cancel. However, trying to replicate an example from a tutorial isn't working. I can't control + drag the Cancel button to the Exit button and use a defined unwind segue. Not quite sure why just yet.
Any ideas on the best way I should be trying to dismiss this view controller?

Simple call
self.dismiss(animated: true, completion: nil)

Related

Dismiss multiple ViewControllers together when using current context as presentation style

I'm creating an application where I place a view controller ontop of another with
Presentation: current context
But when I'm trying to dismiss the screen by dragging the top towards the bottom the view does not disappear.
I've also tried to add a button to make it dismiss but that doesn't work either.
#IBAction func dis(_ sender: Any) {
navigationController?.popViewController(animated: true)
self.dismiss(animated: true)
}
So, how can I dismiss both views when dragging the top one down when it uses "current context" as presentation style?
I'm using "current context" because the previous screen should never be displayed again. And instead of dragging down both, I would like to drag down just one to make both of them disappear. But it does not seem to work as expected.
Although "current context" is not for this purpose as #matt mentioned,
You should dismiss the controller who presents this one to dismiss both together in this case:
self.presentingViewController!.dismiss(animated: true) // `!` is to makeing sure it's not crashing.
Demo:
Use this simple code to demo:
class ViewController: UIViewController {
#IBAction func present() {
let destination = storyboard!.instantiateInitialViewController()!
if presentingViewController != nil {
// You are not in the A
if presentingViewController?.presentingViewController != nil {
// You are in the C
presentingViewController?.presentingViewController?.dismiss(animated: true)
return
} else {
// You are in the B
destination.modalPresentationStyle = .currentContext
}
}
present(destination, animated: true, completion: nil)
}
}
Usage:
Create a single view application
Drag a button into the view controller
Replace the ViewController class with the provided code
Connect the #IBAction
Run it to see the result.
If you use fullscreen presentation (so that there is no drag-to-dismiss) it's quite simple to do this with essentially no code at all.
Note that the yellow view controller appears as an intermediary when presenting, but not when dismissing.

How to pop previous view controller from current view controller?

I have a dashboard, then a login screen and profile screen. Once I reach profile screen I want login screen to be removed so that when I press back button, I am taken to dashboard instead of login. All these are view controllers of a navigation view controller and I display tge using present method.
I have a senario where login can appear anywhere during using navigation. Example: Dashboard, Screen 2, Screen 3, Login, Profile. Here, I have to remove login and when user taps back from profile, it should display Screen 3.
If you are logged-in already and you have to move to top viewController you can do
window.rootViewController.dismiss(animated: true, completion: nil)
But If you are using navigationController then this will work:
navigationController.popToRootViewController(animated: true)
Implement the following in your login view controller:
override func viewWillDisappear(_ animated: Bool) {
var navigationArray = navigationController?.viewControllers
let count = navigationArray?.count
navigationArray?.remove(at: count! - 2)
navigationController?.viewControllers = navigationArray!
}
This removes the current view controller(the login VC in your case) from the navigation stack just when it is about to disappear. So when you tap the back button from the next VC it will always take you to the VC preceding the login.
This is generic answer, not for the answer of this question only.
When popping, you may kick out the viewControllers from your navigation Controller, would solve your problem
extension UINavigationController {
public func removeViewController(classes : [String]) {
var vcs = [UIViewControllers]()
for viewController in self.viewControllers {
let name = viewController.className
if !classes.contains(name) {
vcs.append(viewController)
}
}
if classes.count < vcs.count {
self.viewControllers = vcs
}
}
}
now think you have 3 viewControllers , dashboard, login, profile. you want to remove login and Move Back from profile to dashboard
In profile's View Controller
override func viewDidLoad() {
super.viewDidLoad()
//your works
let viewControllersToRemove = [String(describing: type(of:login))]
navigationController.removeViewController(classes : viewControllersToRemove)
}

How to dismiss 2 modal view controllers without weird animation [duplicate]

This question already has answers here:
Dismissing multiple modal view controllers at once?
(7 answers)
Closed 4 years ago.
I recreated the question and describe its essence more precisely.
I have two view controllers presented modally on Swift 4, without storyboard (can't use unwind) and without navigation controller
A presents B which presents C.
The reason why we don't use navigation controller, it's because we what simple animation from bottom to top and instead of breaking the standard animation from right to left, we decided to use present.
I would like to dismiss 2 view controllers and go from C to A.
Please, don't mark this question as duplicate before you read my question carefully. I found a tone of similar post, but neither solved my problem. Some of them Objective-C or some of the suggest to use:
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
Or:
self.presentingViewController?.dismiss(animated: false, completion: nil)
self.presentingViewController?.dismiss(animated: true, completion: nil)
It's works, but it create weird animation. It's just delete C and animate dismiss for B:
Expected result:
Idea: you need to dismiss third controller with animation and after dismissing you need to dismiss second without animation. While third controller is being dismissed, second shouldn't be visible.
First, set Presentation style of second view controller to Over Current Context when you're presenting it (since we will need to hide its view when we will dismiss third controller)
let vc2 = VC2()
vc2.modalPresentationStyle = .overCurrentContext
present(vc2, animated: true)
continue with creating callbacks properties for willDismiss and didDismiss inside third controller. This callback will be called before and after you dismiss third controller
class VC3: UIViewController {
var willDismiss: (() -> Void)?
var didDismiss: (() -> Void)?
#IBAction func dismissButtonPressed(_ sender: UIButton) {
willDismiss?()
dismiss(animated: true) {
self.didDismiss?()
}
}
}
then in second view controller in the place where you present third view controller, set third controller's callback properties: declare what happens when third controller will dismiss: you need to hide view of second and then after dismissing third you need to dismiss second without animation (view can stay hidden since view controller will be deinitialized)
class VC2: UIViewController {
#objc func buttonPressed(_ sender: UIButton) {
var vc3 = VC3()
vc3.willDismiss = {
self.view.isHidden = true
}
vc3.didDismiss = {
self.dismiss(animated: false)
}
present(vc3, animated: true)
}
}
Anyway, second option is using UINavigationController and then just call its method popToViewController(_:animated:).
Create a snapshot from the currently visible view and add it as a subview to the first presented view controller. To find that you can simply "loop through" the presenting view controllers and dismiss from the initial one:
#IBAction func dismissViewControllers(_ sender: UIButton) {
var initialPresentingViewController = self.presentingViewController
while let previousPresentingViewController = initialPresentingViewController?.presentingViewController {
initialPresentingViewController = previousPresentingViewController
}
if let snapshot = view.snapshotView(afterScreenUpdates: true) {
initialPresentingViewController?.presentedViewController?.view.addSubview(snapshot)
}
initialPresentingViewController?.dismiss(animated: true)
}
This is the result with slow animations enabled for the dismissal:
https://www.dropbox.com/s/tjkthftuo9kqhsg/result.mov?dl=0
If you are not using a navigation controller and you want to dismiss all ViewControllers to show the root ViewController (assuming A is the root):
self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)
Use this in button action method.
The current VC will dismiss when you dismiss the parent VC.
This will dismiss both VCs in single animation.
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)

Navigation pushViewController is not working

i have login view controller. when usersingin i' showing popup for that i
refereed
https://www.youtube.com/watch?v=S5i8n_bqblE i can achieved that.
popup had button when i click the button navigation to next view controller
but its now working when i am clicking that action is performing but its not navigating to next view controller wher i did mistake
Singin
class DigitalGateViewController: NANavigationViewController
{
#IBAction func singin(_ sender: UIButton)
{
let lv = NAViewPresenter().activityVC()
self.present(lv, animated: true)
}
}
this is popupviewcontroller
class ActivityViewController: NANavigationViewController {
#IBAction func okbuttonclick() {
let dv = NAViewPresenter().myGuestListVC()
// self.navigationController?.pushViewController(dv, animated: true)
}
}
its not push to textview controller in swift
When you present a view controller, its presented modally and is not pushed onto the previous navigation controller's stack. Hence, you tried to call self.navigationController?.pushViewController(), it doesn't work, because self i.e. NAViewPresenter().myGuestListVC() isn't embedded in a navigation Controller.
If you want to push the new VC onto the previous stack, you will have to dismiss the presented pop up and then push. The easiest way to do this is to use a delegate method.
Edit:
if you want to create a new navigationController, you can do something like this :
let navController = UINavigationController(rootViewController: NAViewPresenter().myGuestListVC())
present(navController, animated: true)
After presenting the navController, you can use self.navigationController.push method henceforth.
The reason why its not pushing because you are presenting it modally not pushing on the navigation stack and so it wont have any navigationController. If you want to push from your modal popup, you can access the property presentingViewController on your modal object and try to push it on navigationController from there.
self.presentingViewController?.navigationController?.pushViewController(myVC, animated: true)
dismiss(animated: true, completion: nil)

Go back to previous view controller doesn't work

My first view controller has a button, which triggers the #IBAction goTo2ndVc() which presents a second ViewController:
class FirstVC: UIViewController {
...
#IBAction func goTo2ndVc() {
let secondVc = SecondVC(label: "I am second vc.")
self.presentViewController(secondVc, animated: true, completion: nil)
}
When the button is pressed, the 2nd view controller is shown on screen. No problem.
In 2nd view controller, there is also a button which is used to go back to 1st view controller:
class SecondVC: UIViewController {
...
#IBAction func backToFirst(sender: AnyObject) {
print("go back ...")
self.navigationController?.popViewControllerAnimated(true)
}
}
I looked on internet, people suggest to use navigationController?.popViewControllerAnimated(true) to go back to previous controller. But when I press the go back button I can see the print message "go back ..." but the app doesn't go back to 1st view controller. WHY?
#IBAction func backToFirst(sender: AnyObject) {
print("go back ...")
self.dismissViewControllerAnimated(true, completion: nil)
}
In Swift 3
self.dismiss(animated: true, completion: nil)
you should not use navigation controller, because you didn't use it when you were adding the second view controller. that's why simply call dismissViewControllerAnimated method.
You have to use UINavigationController and its pop methods only when you add your view controllers via pushViewController method.
Familiarize yourself with the concept of navigation controller here: https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/NavigationControllers.html
there
the issue is very simple..
self.presentViewController(secondVc, animated: true, completion: nil)
the code will present second view, you are not pushing it.
self.navigationController?.popViewControllerAnimated(true)
the popViewController will pop back to the previous view controller from where it is been pushed.
So, there are two ways you can achieve what you want
1)If you want to present viewController then you have to dismiss the view controller to show previous view controller with
self.dismissViewControllerAnimated(true, completion: nil)
2)If you want to use PopToVewcontroller, then you have to push you second view controller instead of presenting it with
self.navigatioVonroller?.pushViewController(secondVc, animated: true)
If you want to return to the previous view controller, you can simply add:
[self dismissViewControllerAnimated:YES completion:nil];
to the button action method.
If this is added on the nav view controller present on every screen, I see no reason why it shouldn't work as it would always dismiss the most recently presented view.

Resources