Warning: Attempt to present on whose view is not in the window hierarchy!
I have a custom presented view controller and would like to present UIAlertController on top of it. When presenting without custom transition everything works fine.
Tried adding definesPresentationContext = true
without luck
Maybe my custom transition should include something like addChildViewController()
?
First VC
let adVC = AdViewController(with: adView)
adVC.setupAd(with: index)
let adNav = UINavigationController(rootViewController: adVC)
adNav.modalPresentationStyle = .custom
adNav.transitioningDelegate = adVC.adCustomTransition
self.present(adNav, animated: true, completion: nil)
AdViewController
class AdViewController: UIViewController {
var adCustomTransition = AdCustomTransition()
override func viewDidLoad() {
super.viewDidLoad()
definesPresentationContext = true;
submitButton.addTarget(self, action: #selector(presentAlert), for: .touchUpInside)
}
func presentAlert() {
DispatchQueue.main.async {
let alertVC = UIAlertController(title: "Alert!", message: "test alert message", preferredStyle: .alert)
alertVC.view.tintColor = .main
alertVC.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(alertVC, animated: true, completion: nil)
}
}
}
class AdCustomTransition : NSObject, UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return AdAnimationController(withDuration: 0.4, forTransitionType: .present)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return AdAnimationController(withDuration: 0.4, forTransitionType: .dismiss)
}
}
class AdAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
enum TransitionType {
case present, dismiss
}
var duration: TimeInterval
var isPresenting: Bool
init(withDuration duration: TimeInterval, forTransitionType type: TransitionType) {
self.duration = duration
self.isPresenting = type == .present
super.init()
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return self.duration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
let toFrame = transitionContext.finalFrame(for: transitionContext.viewController(forKey: .to)!)
if isPresenting == true {
let toVC = (transitionContext.viewController(forKey: .to) as! MainNavigationController).viewControllers.first as! AdViewController
containerView.addSubview(toVC.view)
containerView.layoutIfNeeded()
let bottomHeight = toVC.getSafeBottomHeight()
let offset = toVC.containerView.bounds.height - 120 - bottomHeight
toVC.containerView.transform = CGAffineTransform(translationX: 0, y: offset)
UIView.animate(withDuration: self.duration, delay: 0, usingSpringWithDamping: 5.4, initialSpringVelocity: 0.8, options: .curveEaseInOut, animations: {
toVC.containerView.transform = CGAffineTransform(translationX: 0, y: -1 * bottomHeight)
}, completion: { (_) in
toVC.view.frame = toFrame
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
} else {
let fromVC = (transitionContext.viewController(forKey: .from) as! MainNavigationController).viewControllers.first as! AdViewController
let toVC = transitionContext.viewController(forKey: .to)!
containerView.addSubview(toVC.view)
containerView.addSubview(fromVC.view)
containerView.layoutIfNeeded()
let bottomHeight = fromVC.getSafeBottomHeight()
let offset = fromVC.containerView.bounds.height - 110 - bottomHeight
fromVC.containerView.transform = .identity
UIView.animate(withDuration: self.duration, delay: 0, usingSpringWithDamping: 5.7, initialSpringVelocity: 0.8, options: .curveEaseInOut, animations: {
fromVC.containerView.transform = CGAffineTransform(translationX: 0, y: offset)
}, completion: { (_) in
toVC.view.frame = toFrame
UIApplication.shared.keyWindow?.addSubview(toVC.view)
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
}