mink23
mink23

Reputation: 154

Custom VC Transition not Dismissing Properly

I am trying to recreate the stock UIAlertAction in a VC with a custom transition. I currently have the presenting working perfectly(backgroundView fades in and the 'notification' VC slides from the bottom). The problem I am facing is when I dismiss the VC the backgroundView doesn't fade out. It's as if it's completely bypassing my animation block. Once completeTransition is called the backgroundView disappears completely. What is happening?

class AnimationController: NSObject {
 let backgroundView = UIView()
}

extension AnimationController:  UIViewControllerAnimatedTransitioning {
  func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let containerView = transitionContext.containerView

    guard let toViewController = transitionContext.viewController(forKey: .to),
        let fromViewController = transitionContext.viewController(forKey: .from) else {
            transitionContext.completeTransition(false)
        return
    }
    switch animationType {
    case .present:
        backgroundView.frame = CGRect(x: 0, y: 0, width: toViewController.view.frame.width, height: fromViewController.view.frame.height)
        backgroundView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
        backgroundView.alpha = 0
        containerView.addSubview(backgroundView)

        let viewToAnimate = toViewController.view!
        containerView.addSubview(viewToAnimate)

        toViewController.view.clipsToBounds = true

        viewToAnimate.frame = CGRect(x: 0, y: viewToAnimate.frame.maxY, width: viewToAnimate.frame.width, height: viewToAnimate.frame.height)

        let duration = transitionDuration(using: transitionContext)

        UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations:  {
            self.backgroundView.alpha = 1.0
            viewToAnimate.transform = CGAffineTransform(translationX: 0, y: -viewToAnimate.frame.height)
        }) { _ in
            transitionContext.completeTransition(true)
        }
    case .dismiss:

        containerView.addSubview(fromViewController.view!)

        let testView = fromViewController.view!

        backgroundView.frame = CGRect(x: 0, y: 0, width: testView.frame.width, height: testView.frame.height)
        backgroundView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)

        let duration = transitionDuration(using: transitionContext)

        UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations:  {
            self.backgroundView.alpha = 0.0
            testView.transform = CGAffineTransform(translationX: 0, y: testView.frame.height)
            print("backgroundView Doesn't fade out")
        }) { _ in
            print("backgroundView disappears here")
            transitionContext.completeTransition(true)
        }
    }
}

Upvotes: 3

Views: 582

Answers (3)

Rob C
Rob C

Reputation: 5073

Your problem is that you're dealing with two separate instances of your AnimationController and hence two separate instances of backgroundView. One instance is instantiated for presentation and the other is instantiated for dismissal. Notice in your case .present: block you are calling containerView.addSubview(backgroundView) but you don't do the same in the case .dismiss: block. As a result, the backgroundView instance in the case .dismiss: block isn't even part of the view hierarchy.

What you need to do is call self.backgroundView.removeFromSuperview() in your first animation completion block. Then in your case .dismiss: you need to call containerView.addSubview(backgroundView) once again.

Try this...

    switch animationType {
    case .present:

        // ...

        containerView.addSubview(backgroundView)

        // ...

        UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations:  {
            self.backgroundView.alpha = 1.0
            viewToAnimate.transform = CGAffineTransform(translationX: 0, y: -viewToAnimate.frame.height)
        }) { _ in
            self.backgroundView.removeFromSuperview()
            transitionContext.completeTransition(true)
        }
    case .dismiss:

        // ...

        containerView.addSubview(backgroundView)

        containerView.addSubview(fromViewController.view!)

        // ...

        UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations:  {
            self.backgroundView.alpha = 0.0
            testView.transform = CGAffineTransform(translationX: 0, y: testView.frame.height)
            print("backgroundView Doesn't fade out")
        }) { _ in
            print("backgroundView disappears here")
            transitionContext.completeTransition(true)
        }
    }

Upvotes: 1

Amul4608
Amul4608

Reputation: 1448

Try This

for present replace this code

    backgroundView.frame = CGRect(x: 0, y: 0, width: toViewController.view.frame.width, height: fromViewController.view.frame.height)
    backgroundView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
    backgroundView.alpha = 0
    containerView.addSubview(backgroundView)

    let transition = CATransition()
    transition.duration = 0.5
    transition.type = CATransitionType.moveIn
    transition.subtype = CATransitionSubtype.fromTop
    containerView.layer.add(transition, forKey: kCATransition)

For Dismiss Replace this code

  containerView.addSubview(fromViewController.view!)
  let transition = CATransition()
  transition.duration = 0.5
  transition.type = CATransitionType.fade
  containerView.layer.add(transition, forKey: kCATransition)
  backgroundView.frame = CGRect(x: 0, y: 0, width: testView.frame.width, height: testView.frame.height)
  backgroundView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)
  self.backgroundView.alpha = 0.0

Upvotes: 0

you could try to present like this

//where DevolucionVC is you ViewController 
    if let controller = DevolucionVC() as? DevolucionVC {
                if let window = self.window, let rootViewController = window.rootViewController {
                    var currentController = rootViewController
                    while let presentedController = currentController.presentedViewController {
                        currentController = presentedController
                    }
                    currentController.present(controller, animated: true, completion: nil)
                }
            }

you can dismiss it later by simply use

 dismiss(animated: true, completion: nil)

Upvotes: 0

Related Questions