Search code examples
iosswiftanimationuiviewcontrolleruiviewanimationtransition

Custom UINavigationController Animation Unresponsive When Finished


I'm trying to make a slide animation for my navigation controller transitions. For instance, when I push a VC, the presenting and the presented VCs will transition just like a UIPageViewController transition.

Here is what I've coded so far:

guard let fromView = transitionContext.view(forKey: .from),
      let toView = transitionContext.view(forKey: .to)
  else { return }

  let containerView = transitionContext.containerView

  toView.frame = CGRect(x: -toViewFrameHorizationtalPosition,
                        y: 64,
                        width: UIScreen.main.bounds.width,
                        height: UIScreen.main.bounds.height)

  containerView.addSubview(fromView)
  containerView.addSubview(toView)

  UIView.animate(withDuration: transitionDuration(using: transitionContext),
                 delay: 0,
                 options: .curveEaseInOut,
                 animations: {
                   containerView.frame.origin.x = self.toViewFrameHorizationtalPosition
  }) { completed in
    transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
  }

The transition animation is happening as I expected it to be but even though against various tries, once the animation executes the view becomes unresponsive; it does not recognise any touch events.

The navigation bar works fine but when I switch back to the initial view, that view is unresponsive as well.

I've read a lot on this and been struggling with this for a while now although I can't seem to spot the issue. Any ideas?


Solution

  • Alright then, I finally found the solution. Many many thanks to @DonMag for pointing me in the right direction with his great comment!

    First off, as @DonMag has also mentioned, it was needless of me to add the fromView into the containerView as it's already present inside there.

    Anyways, the problem with the presented view, toView, being unresponsive was that for the purposes of making the slide animation:

    • I was changing the x value of the toViews frame origin to position it right inside the container view,
    • and moving the container view again by changing it's x value of it's frame origin. I'm moving the container view because I want both the fromView and the toView to act one next to the other, i.e. just like how a UIPageViewController animates.

    The problem was that I was not setting them back to their original values. Once I set toViews and containerViews frame origins back to their original values in the animation completion block, everything worked as expected.

    Here is the revised animation code:

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toView = transitionContext.view(forKey: .to)
            else { return }
    
        toView.removeFromSuperview()
        toView.frame = CGRect(x: -toViewFrameHorizationtalPosition,
                              y: 64,
                              width: UIScreen.main.bounds.width,
                              height: UIScreen.main.bounds.height)
    
        let containerView = transitionContext.containerView
        containerView.addSubview(toView)
    
        UIView.animate(withDuration: transitionDuration(using: transitionContext),
                       delay: 0,
                       options: .curveEaseInOut,
                       animations: {
                                        containerView.frame.origin.x = self.toViewFrameHorizationtalPosition
        }) { completed in
            containerView.frame.origin.x = 0
            toView.frame.origin.x = 0
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }
    }
    

    P.S. Again, many many thanks to @DonMag. Your insight has been really helpful.