[Big help!]Custom transition animation not triggered when VC present

Hello guys! :slight_smile:

I want make some change to source code for 17-custom-presentation-controller to make custom transition animation,all my change is in class PopAnimator.

This is my change:

  1. add a new instance variable in PopAnimator to save transitionContext:

    var ctx:UIViewControllerContextTransitioning!

  2. I rewrite the method:

animateTransition(using transitionContext: UIViewControllerContextTransitioning)

to this :

func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    let containerView = transitionContext.containerView
    let toView = transitionContext.view(forKey: .to)!
           
    //save transitionContext
    ctx = transitionContext
    
    containerView.addSubview(toView)
    
    let animation = CATransition()
    animation.duration = duration / 2

    animation.type = "cube"
    //use type kCATransitionReveal is not work too ...
    //animation.type = kCATransitionReveal

    animation.subtype = kCATransitionFromLeft
    animation.delegate = self
    
    containerView.layer.add(animation, forKey: nil)
}

3.Last I make class PopAnimator confirm CAAnimationDelegate delegate, and add the new method:

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    if ctx != nil{
        //make transition complete
        ctx.completeTransition(true)
        dismissCompletion?()
    }
}

When run the App,the transition animation is look good when detailsVC dismiss,but nothing happened when presenting detailsVC!

You can see the demo above : when user tap the bottom left green view,it present detailsVC,but no animation happened!!! but when dismiss detailsVC,the animation work fine!

What’s wrong with it???
and how to fix it???

my code is in here : GitHub - hopy11/TransitionTest: Test VC transition animations

thanks a lot! :wink:

1 Like

@hopy. Thanks very much for your question!

I took a brief look at your code, and I did notice that you’ve commented several lines of code that may be the reason. For example:

//transition.reverse = false

Have you tried uncommenting this line, and others like it to see what happens? When it comes to debugging, I would recommend placing a break point, and see what method is called when you dismiss the detailsVC, and then check to see which method is called when presenting it? That would be the first step to identify what the problem is.

I hope this helps!

All the best!

Thanks for your answer!

Those commented lines is original example code of the book. as your word,I tried a lot combination of transition’s parameter,but not working…

I poked it for 20 minutes, but no luck. So kudoz to the one who figures why it works in one case and does not in the other.

@hopy I know this is probably not exactly what you’re looking for, but just in case you don’t know about this: you can use CATransition without all these animated transitioning dancing, just like so:

    let t = CATransition()
    t.duration = 0.4
    t.type = "cube"
    t.subtype = kCATransitionFromLeft
    view.window?.layer.add(t, forKey: nil)
    
    present(vc, animated: false, completion: nil)

Cheers

Thanks ! I’ll try it!!!

By the way : Is my questuon is very hard???

As the author of this book should be very clear what is going on… :frowning:

Hey @hopy
Well, I’m not the author :slight_smile:

Good news, though, I’ve figured it would work with UIViewControllerAnimatedTransitioning like this:

  1. create new func animate(transitionContext: UIViewControllerContextTransitioning) {}
  2. move all the code from func animateTransition(using transitionContext: UIViewControllerContextTransitioning) to func animate(transitionContext: UIViewControllerContextTransitioning)
  3. In animateTransition call animate with slight delay like so:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.001) {
    self.animate(transitionContext: transitionContext)
}

And it works. I guess it’s some quirk of CATransition.

Thank you!

I follow your code ,but it not work for me…

This is my changed code according to your solution :

import UIKit

extension PopAnimator:CAAnimationDelegate{
  func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
      if ctx != nil{
          if !presenting{
              dismissCompletion?()
          }
          ctx.completeTransition(true)
      }
  }
}

class PopAnimator: NSObject,UIViewControllerAnimatedTransitioning {
  
  let duration = 1.0
  var presenting = true
  var originFrame = CGRect.zero
  var ctx:UIViewControllerContextTransitioning!
  
  var dismissCompletion:(()->())?
  
  func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
      return duration
  }
  
  func animate(transitionContext:UIViewControllerContextTransitioning){
      let containerView = transitionContext.containerView
      let toView = transitionContext.view(forKey: .to)!
      
      containerView.addSubview(toView)
      
      let animation = CATransition()
      animation.duration = duration / 2.0
      animation.type = "cube"
      if presenting{
          animation.subtype = kCATransitionFromLeft
      }else{
          animation.subtype = kCATransitionFromRight
      }
      
      animation.delegate = self
      ctx = transitionContext
  }
  
  func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
      
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.5){
          self.animate(transitionContext: transitionContext)
      }
  }
}

something wrong???

@hopy the code works. You’ve missed to add the animation in the end:
containerView.layer.add(animation, forKey: nil)

Also, you don’t have to use delay like 0.5, something like 0.01 should do. On simulator, delay of 0.001 works.

Ok,you’re right!!!
But why use containerView.layer.add(animation, forKey: nil) instead of toView or fromView ???
Thanks!

1 Like

Ok,I know it!
Thank you anyway :grinning:

1 Like

This topic was automatically closed after 166 days. New replies are no longer allowed.