Reputation: 15992
I have found many related topics on SO (and elsewhere) but still couldn't find a solution to my problem. I want to display a custom alert on my view using UIViewControllerTransitioningDelegate
. So first, in my initial view controller, here is the call:
@IBAction func tappedButton(_ sender: Any) {
MyAlertViewController.presentIn(viewController: self)
}
And here the code of MyAlertViewController
:
import UIKit
open class MyAlertViewController: UIViewController, UIViewControllerTransitioningDelegate {
@IBOutlet weak var overlayView: UIView?
@IBOutlet weak var alertView: UIView?
@IBOutlet weak var alertCenterYConstraint: NSLayoutConstraint?
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: "MyAlertView", bundle: nil)
self.transitioningDelegate = self
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static func presentIn(viewController: UIViewController) {
let alertViewController = MyAlertViewController()
if Thread.isMainThread {
viewController.present(alertViewController, animated: true, completion: nil)
} else {
DispatchQueue.main.async {
viewController.present(alertViewController, animated: true, completion: nil)
}
}
}
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MyDismissAlertViewAnimationController()
}
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MyPresentAlertViewAnimationController()
}
}
class MyPresentAlertViewAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}
public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let toViewController: MyAlertViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to) as! MyAlertViewController
let duration = self.transitionDuration(using: transitionContext)
let containerView = transitionContext.containerView
toViewController.view.frame = containerView.frame
containerView.addSubview(toViewController.view)
toViewController.overlayView?.alpha = 0.0
UIView.animate(withDuration: duration, animations: {
toViewController.overlayView?.alpha = 0.6
})
let finishFrame = toViewController.alertView?.frame
var startingFrame = finishFrame
startingFrame?.origin.y = -((finishFrame?.height)!)
toViewController.alertView?.frame = startingFrame!
UIView.animate(withDuration: 0.5, delay: 0.0, usingSpringWithDamping: 0.7, initialSpringVelocity: 1.0, options: .layoutSubviews, animations: {
toViewController.alertView?.frame = finishFrame!
}, completion: { result in
transitionContext.completeTransition(result)
})
}
}
class MyDismissAlertViewAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}
public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let fromViewController: MyAlertViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) as! MyAlertViewController
let duration = self.transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration, animations: {
fromViewController.overlayView?.alpha = 0.0
})
var finishFrame = fromViewController.alertView?.frame
finishFrame?.origin.y = -(finishFrame?.height)!
finishFrame?.origin.y = fromViewController.isDismissingByBottom ? fromViewController.view.frame.size.height : -(finishFrame?.height)!
UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .layoutSubviews, animations: {
fromViewController.alertView?.frame = finishFrame!
}, completion: { result in
transitionContext.completeTransition(true)
})
}
}
The animation works fine, the black screen only appears after the call to completeTransition()
as you can see below:
Thanks for your help...
Upvotes: 0
Views: 993
Reputation: 3687
I think you need to either set your background color like so:
self.view.backgroundColor = .clear
This will make sure the background you see is not just the background color of your modal.
Or prevent the presenting view controller to be removed from the screen by making the modal presentation style overCurrentContext
self.modalPresentationStyle = .overCurrentContext
Upvotes: 1