Hello I am pretty annoyed with this:
Originally, I had many segues in my storyboard. Each button at bottom of tool bar would segue to various view controllers. As you can imagine, that is a lot of segues for 6 different items on toolbar. After segueing, each action would call self.dismiss and everything would be ok.
Recently, I wanted to clean up the storyboard.
I created the function:
extension UIViewController {
func segue(StoryboardID: String) {
let popOverVC = UIStoryboard(name: "Main", bundle:
nil).instantiateViewController(identifier: StoryboardID)
popOverVC.modalPresentationStyle = UIModalPresentationStyle.fullScreen
popOverVC.modalTransitionStyle = .crossDissolve
self.dismiss(animated: false, completion: nil)
print("dismissed")
self.present(popOverVC, animated: false, completion: nil)
print("presented")
}
}
What I am seeing is that the dismiss dismisses the new view controller from appearing. It essentially goes back to my first view controller presented upon launch. I want to dismiss all view controllers so that I don't keep piling up my views.
Thanks
The problem is that you present your popOverVC from a view controller that is being dismissed, so your popOverVC will never be shown as its parent is being dismissed.
Not sure how your architecture is exactly but you would either need to use the delegate pattern to tell the parent when to segue, for example:
self.dismiss(animated: true) {
self.delegate?.didDismiss(viewController: self)
}
Or to use some trick to get the top most view controller to present your popOverVC after the current view has been dismissed, ex:
self.dismiss(animated: true) {
var topController: UIViewController = UIApplication.shared.windows.filter{$0.isKeyWindow}.first!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
topController.present(popOverVC, animated: true)
}
But I agree with #Paulw11, a UITabBarController seem like a much better option for what you're trying to do.
Related
I have two view controllers, first view controller and the second view controller, when the user segue from the first view controller to the second view controller, the first view controller still visible and sits behind the second view controller. The user can swipe the first view controller and see the entire first view controller and then they got stuck there. I noticed that this only happens after the launch of iOS 13.
performSegue(withIdentifier: "showSecond", sender: self)
Follow these two steps:
Click on the segue you created on the Storyboard
Go to Attributes Inspector
Set the Presentation to "Full Screen"
#Maysam is 100% right! But you can also do it programmatically through this:
// Go to next View Controller
#IBAction func nextTextVC(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nextInfo = storyboard.instantiateViewController(identifier: "socialOptionsIntroViewController")
self.navigationController?.pushViewController(nextInfo, animated: true)
}
There is a more detail thread could answer this question.
The follow solution from Pratik Sodha
let controller = UIViewController()
let navigationController = UINavigationController(rootViewController: controller)
navigationController.modalPresentationStyle = .overCurrentContext
self.navigationController?.present(navigationController, animated: true, completion: nil)
so I have a main view controller that the view controllers will present inFront of each other and I want when user click the button in the last view controller close all of the presented modally view controllers so I used this code But I didn't get the result
let destination = matchViewController()
let appDelegate:UIApplicationDelegate = UIApplication.shared.delegate!
let initialViewController = destination
let navigationController = UINavigationController(rootViewController: initialViewController)
appDelegate.window??.rootViewController = navigationController
appDelegate.window??.makeKeyAndVisible()
I want to use unwind segue to exit But there is another problem too
the last view controller will present many times in many different situations so I just to dismiss all presented modally view controllers in. this situation
I rather not using the navigationController But if I had to use it pleas tell me where exactly should I use that ?
Two options:
Dismiss all view controllers on the root view controller
self.view.window?.rootViewController?.dismiss(animated: true, completion: nil)
Dismiss all viewControllers until it has a presentingController
func dismissAllControllers() {
guard let vc = self.presentingViewController else { return }
while (vc.presentingViewController != nil) {
vc.dismiss(animated: true, completion: nil)
}
}
Let say I have the following VCs:
RootVC --> VC A --> VC B
I'm using present method to present view controller from RootVC to VC A then to VC B. Now I'm on VC B and I want to dismiss from VC B back to RootVC using
self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
it works but I still see VC A shows up during the dismiss process. Then, I try this method
self.presentationController?.presentedViewController.dismiss(animated: true, completion: nil)
It also works to dismiss back to root VC but I still see VC A in process.
My question is is there a way to not show VC A during the dismiss process? I already try animated: false but still get the same result. Thanks!
You need to make the change in the modalPresentationStyle to the .custom. The custom will allow you to view the presentingViewController view when the current visible controller's view is transparent.
Now when you want to go back to root view on the current presenting stack you need to call the method dismissToRootViewController(animated: completion:).
In the implementation of this method will allow all intermediate presenting view controller view to be transparent which will give you dismiss animation from VC c to RootVC.
extension UIViewController {
func dismissToRootViewController(animated: Bool, completion: (() -> Swift.Void)? = nil) {
var viewController = self.presentingViewController
while viewController?.presentingViewController != nil {
viewController?.view.alpha = 0.0
viewController = viewController?.presentingViewController
}
self.dismiss(animated: true) {
viewController?.dismiss(animated: false, completion: completion)
}
}
}
You can try to use this:
navigationController?.popToRootViewController(animated: false)
I have a view controller that shows the details of an object. On this view controller is an "edit" button which shows modally the edition view controller. When I try to dismiss the modally presented view (edit view controller) :
self.dismissViewControllerAnimated(true, completion: nil)
I get the following error and it's presenting my initial viewController instead :
Warning: Attempt to present ≤Deevent.MyEventsVC: 0x7f99b70160a0≥ on ≤Deevent.EventCreationVC: 0x7f99b7238690≥ whose view is not in the window hierarchy!
So what I've tried was to set the root view controller of my view to the view I wanted to go back and present it in the completition of my dismiss. It's working well, but my application is in a Tabbar Controller and now it's not in it anymore. Same for the navigation controller.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("MyEventsStoryboard") as! MyEventsVC
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
appDelegate.window?.rootViewController = vc
self.dismissViewControllerAnimated(false, completion: {
self.presentViewController(vc, animated: true, completion: nil)
})
Is there an other approach for presenting viewControllers after dismiss without leaving the Tabbar controller ?
Thanks
Since you are trying to present the new view controller by calling self.presentViewController after you dismiss self, you get the error. I can offer you a solution if you are using a navigation controller.
I have a problem, where I have two view controllers A and B. View controller B has a map, with a route draw on it. I can move back and forwards between the two view controllers at the moment, but the B view controller is reset every time it loads. I think this is because I am using segues and it is creating a new instance of a View controller every time.
I have tried using the following code to solve this issue, but it is still not working. The views load correctly, but view controller B is still being reset
#IBAction func mapButton(sender: AnyObject){
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UIViewController
self.presentViewController(vc, animated: true, completion: nil)
}
What am I doing wrong and how can I fix it? I want view controller B to stay in the memory along with the map and the route, so when a user returns he doesn't have to enter all of the information again.
You should create a variable in your class of type UIViewController and change your code to the following:
#IBAction func mapButton(sender: AnyObject){
if yourVariable == nil {
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
yourVariable = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UIViewController
}
self.presentViewController(yourVariable, animated: true, completion: nil)
}
That way you create the viewController one time, save it and if you want to open it again present the previously created one.