Popover on a Popover issue while tap on notification(Deeplink) - ios

I have already presented a controller on the screen and now click on the home button. Then I need to present another controller on that after tapping on notification using deeplink.
When app comes to foreground, new controller is nor presented and previous controller is also dismissed.
Getting below Warning as well:-
Attempt to present <NewController> on <PreviousController> whose view is not in the window hierarchy!
I am using below code to present.
controller.transitioningDelegate = myDelegateForTransition
controller.modalPresentationStyle = .custom
controller.modalPresentationCapturesStatusBarAppearance = true
viewControllerFromPresent.present(controller, animated: true, completion: {
completionHandler?()
})

I resolved it by changing controller.modalPresentationStyle from custom to overCurrentContext.
controller.transitioningDelegate = myDelegateForTransition
controller.modalPresentationStyle = .overCurrentContext
controller.modalPresentationCapturesStatusBarAppearance = true
viewControllerFromPresent.present(controller, animated: true, completion: {
completionHandler?()
})

Related

How to check if a view controller has been dismissed in Swift

If I present a ViewController like so:
let authViewController = authUI!.authViewController()
authViewController.modalPresentationStyle = .overCurrentContext
self.present(authViewController, animated: true, completion: nil)
I would like to know when the ViewController has been dismissed. I have tried the following:
let authViewController = authUI!.authViewController()
authViewController.modalPresentationStyle = .overCurrentContext
self.present(authViewController, animated: true, completion: {
print("View Dismissed")
})
but that only lets me know if the view was presented successfully. This ViewController was not created by me so I can't change the viewWillDissapear method.
Whole answer is predicated on an assumption that OP doesnt have access to authViewController code
If you dont have access to authViewController code, lousy solution would be to use viewWillAppear of your view controller to find when auth view controller is dismissed.
Basically when you present/push any viewController over your existing view controller, your view controller's viewWillDisappear will be called similarly when presented/pushed view controller is dismissed, or popped out viewWillAppear will be called.
Because viewWillAppear might get called for other reasons as well and you wouldnt wanna confuse it as authViewController dismiss, use a boolean
private var shouldMonitorAuthViewControllerDismiss = false //declared a instance property
Set the boolean to true when you actually present the authViewController
let authViewController = authUI!.authViewController()
authViewController.modalPresentationStyle = .overCurrentContext
self.present(authViewController, animated: true, completion: {
shouldMonitorAuthViewControllerDismiss = true
})
Finally in your viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if shouldMonitorAuthViewControllerDismiss {
//auth view controller is dismissed
}
shouldMonitorAuthViewControllerDismiss = false
}

Swift: Presenting VC in completion handler of dismissal

I have the following ViewController (VC) flow:
SplashScreen/launch VC -> Login VC (on notification, present) -> SplashScreenVC -> Main VC
I want to avoid using an unwind segue because I will need to regularly re-authenticate the user regardless of current VC and so would much rather programatically 'present'.
The problem is, I am able to present and dismiss the SplashScreen VC (which is originally the root) but then cannot do the same for the Login VC without an error.
Code:
//in SplashScreen VC viewDidAppear
let loginVC = myStoryboard.instantiateViewController(identifier: "loginVC") as UIViewController
loginVC.modalPresentationStyle = .fullScreen
loginVC.modalTransitionStyle = .coverVertical
//dismissal?
self.dismiss(animated: true, completion: {
self.present(loginVC, animated: true, completion: nil)
})
//in loginVC selector function
let launchVC = myStoryboard.instantiateViewController(identifier: "launchVC") as UIViewController
launchVC.modalPresentationStyle = .fullScreen
launchVC.modalTransitionStyle = .coverVertical
//check for top view controller (debugging)
print("TOPVC at LoginVC: \(self.getTopVC()!)")
//handle dismissal?
self.dismiss(animated: true, completion: {
self.present(launchVC, animated: true, completion: nil)
})
WARNING:
Warning: Attempt to present <Slidr.LaunchScreenViewController: 0x15be0ef90> on <Slidr.LoginViewController: 0x15be6b510> whose view is not in the window hierarchy!
Warning: Attempt to present <Slidr.TestingViewController: 0x15db00ac0> on <Slidr.LaunchScreenViewController: 0x15bd06960> whose view is not in the window hierarchy!
Code runs fine if I don't dismiss the loginVC but I would like to avoid residue controllers over time.
I've tried to present from the top VC rather than 'self' but that doesn't seem to change anything.
Any help would be much appreciated.
As error says you need to present a vc from a 1 that's currently dismissed , so instead do
self.dismiss(animated: true, completion: {
(UIApplication.shared.delegate as! AppDelegate).window?.rootViewController = loginVC
}
Another way also is to embed rootVC inside a navigationController and do
self.navigationController?.setViewControlls([loginVC],animated:true)

New iOS 13 Modal Presentation: Presenting Controller Doesn't Move Down

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/

Present and Dismiss with different modal styles

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

Swift How to present view in root navigation after dismiss modal

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)
})

Resources