I have a weird behavior when presenting UIViewControllers modally in iOS 13. The new presentation style that I've seen all across iOS 13 looks like this:
The presenting view controller appears behind the presented view controller. It is also shifted down to mimic a "stack"
Meanwhile, when presenting view controllers through my app, I keep getting this effect:
The presenting view controller doesn't move at all when presenting a new view controller
I use this code to present this view controller:
let controller = storyboard?.instantiateViewController(withIdentifier: "tutorial") as! TutorialController
controller.modalPresentationStyle = .pageSheet
controller.modalTransitionStyle = .coverVertical
present(controller, animated: true, completion: nil)
Here is my question:
I'm wondering why this is happening and if there is a way to present view controllers in the normal iOS 13 style (with the presenting view controller moving back).
Thanks in advance!
Turns out the problem was my view controller hierarchy. I was able to fix it by making the presenting view controller the root view controller of my app. First I set the background controller as the root view controller by calling
window.rootViewController = self
and then using my previous code
let controller = storyboard?.instantiateViewController(withIdentifier: "tutorial") as! TutorialController
controller.modalPresentationStyle = .pageSheet
controller.modalTransitionStyle = .coverVertical
present(controller, animated: true, completion: nil)
I presented the view controller. Thanks to everyone who tried to help!
I think the issue can be resolved by using vc.modalPresentationStyle = .fullScreen if there is not UINavigationController , otherwise you can use these codes as follows:
let navigationController = UINavigationController(rootViewController: vc)
navigationController.modalPresentationStyle = .fullScreen
present(vc, animated: true)
because With iOS 13 this is a new feature that Apple has changed the default presentation style of View Controllers to a modal sheet from fullscreen in iOS 12
Programmatically:
let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen //or .overFullScreen for transparency
self.present(vc, animated: true, completion: nil)
From storyboard:
That's it. No need to play with root controller or window at all.
For reference, visit this article.
iOS13: Let's say you have 3 view controllers: FirstVC, SecondVC, ThirdVC
FirstVC presents SecondVC with the below code:
let secondVC = SecondVC()
secondVC.modalPresentationStyle = .fullScreen
firstVC.present(secondVC, animated: true, completion: nil)
SecondVC presents ThirdVC with the below code:
let thirdVC = ThirdVC()
secondVC.present(thirdVC, animated: true, completion: nil)
Changing secondVC's modalPresentationStyle to .currentContext solves the problem.
We can change it in the Inspector Tool Bar. To Achieve it: head over to the fifth section of Inspector Tollbar then change the Presentation field to Full Screen.
This should be the only property you need to set
presentedViewController.modalPresentationStyle = .automatic
Detailed in
https://developer.apple.com/videos/play/wwdc2019/224/
Related
I am trying present a navigation controller with UITabBarController, I am confused why UITabBarController's viewDidAppear is not called again after the navigation controller dismissed. How can I manage to do that?
Change presentation style to currentContext. For example:
let controller = ViewController()
controller.modalPresentationStyle = .currentContext //<-- Add this line
self.present(controller, animated: true, completion: nil)
I want to be able to present a viewController with crossDissolve but dismiss it with the traditional top to bottom dismissal.
Is there a way to change the modalTransitionStyle once the viewController has opened?
Here is how I am currently presenting
I want to be able to present a viewController with crossDissolve but dismiss it with the traditional top to bottom dismissal.
Is there a way to change the modalTransitionStyle once the viewController has opened?
Here is how I am currently presenting
let layout = UICollectionViewFlowLayout()
let userSearchController = UserSearchController(collectionViewLayout: layout)
userSearchController.modalTransitionStyle = .crossDissolve
currentController?.present(userSearchController, animated: true, completion: nil)
Using #Jason's comment I did the following
userSearchController.modalTransitionStyle = .crossDissolve
currentController?.present(userSearchController, animated: true, completion: {
userSearchController.modalTransitionStyle = .coverVertical
})
and it works perfectly
I'm trying to make ViewController present after Modal dismiss
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let chatRoomVC = storyboard.instantiateViewController(withIdentifier: "ChatRoomVCId") as! ChatRoomVC
chatRoomVC.hidesBottomBarWhenPushed = true
chatRoomVC.passValue = passValue
self.dismiss(animated: true, completion: {
self.present(chatRoomVC, animated: true, completion: nil)
})
But it will return "whose view is not in the window hierarchy!" maybe it's present a view after the controller dismissed
Notice the self in self.present, what you are doing, is basically tell the vc that you are dismissing to present a new vc, thats wrong way to do, the correct way is tell it's PARENT vc to present a new vc, by using delegate/unwind to call the parent vc to present new vc
You are using self. It means you are dismissing the current view controller. It should be the parent view controller who will present a new view controller.
When present from "Controller_A" to "Controller_B"-> present it like given below
--- View Controller A ---
self.navigationController?.present(Controller_B, animated: true, completion: nil)
When you want to dismiss "Controller_B" and present "Controller_C" using Navigation controller
--- View Controller B ---
let presenController : UINavigationController = self.presentingViewController as! UINavigationController
presentingController.dismiss(animated: true, completion: {
presenController.pushViewController(Controller_C, animated: true)
})
With the following code I'm able to change the rootViewController behind a modal view :
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let signupVC = storyboard.instantiateViewControllerWithIdentifier("SignupNavigationController") as! UINavigationController
let landingPageVC = storyboard.instantiateViewControllerWithIdentifier("LandingPage") as! LandingPageViewController
presentViewController(signupVC, animated: true, completion: {
UIApplication.sharedApplication().delegate?.window??.rootViewController = landingPageVC
UIApplication.sharedApplication().delegate?.window??.sendSubviewToBack(landingPageVC.view)
})
When I close my modal view controller it's the previous rootViewController that is displayed (only during the animation). Then my new view controller is displayed properly.
Any idea how I could prevent this ?
Answering to myself,
The view I can see during the modal animation is something like a snapshot. I found out that the view is not visible in Xcode's view hierarchy debugger, thus the view is not present in the viewController tree.
To refresh this snapshot I had to set the modalPresentationStyle to .OverFullScreen
myModalViewController.modalPresentationStyle = .OverFullScreen
I present a View Controller in the following fashion:
let vc: ChangeDateViewController = storyboard!.instantiateViewControllerWithIdentifier("changedate") as! ChangeDateViewController
let navigationController = UINavigationController(rootViewController: vc) //ensures that the top navigation bar remains in the new View Controller
self.presentViewController(navigationController, animated: true, completion: nil)
For some reason, the base presenting View Controller slides down while the new View Controller is sliding up. Although the presenting works, it does look glitchy because the sliding down reveals the black background behind the views. Is this a common occurrence, and is there anything I can do to prevent it?
Try this:
let storyboard1 = UIStoryboard(name: "Main", bundle: nil)
let conn = storyboard1.instantiateViewControllerWithIdentifier("changedate") as! LMAddaccountMainVC
self.presentViewController(conn, animated: true, completion: nil)
This might be helpful to solve you issue.