Search code examples
iosswiftuicollectionviewuistoryboardsegue

After custom modal dismissal transition the first view controller's lifecycle methods don't get called


I have two view controllers: viewController1 and viewController2. viewController1 contains a collection view with several cells.

They are connected by a modal segue. For navigation between them I create two animators for showing viewController2 (showAnimator) and for dismissing it (dismissAnimator).

In dismissAnimator I animate both the fromView (viewController2's view) and toView (viewController1's view). Here are the two methods for doing that:

 private func animateFromViewDisappearance(fromView: UIView?, withDuration duration: TimeInterval, usingTransitionContext transitionContext: UIViewControllerContextTransitioning?) {
    guard let containerView = transitionContext?.containerView, let fromView = fromView else {return}

    UIView.animate(withDuration: duration, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
        fromView.transform = CGAffineTransform(scaleX: 1.5, y: 1.5)
        fromView.alpha = 0.0
    }, completion: {_ in

    })
}

 private func animateToViewAppearance(toView: UIView?, withDuration duration: TimeInterval, usingTransistionContext transitionContext: UIViewControllerContextTransitioning?) {
    guard let containerView = transitionContext?.containerView, let toView = toView else {
        return}


    toView.frame = containerView.frame
    toView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
    toView.alpha = 0.0
    containerView.addSubview(toView)

    UIView.animate(withDuration: duration, delay: 0.3, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .curveEaseInOut, animations: {
        toView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
        toView.alpha = 1.0
    }) { (success) in
        if success {
            transitionContext?.completeTransition(true)
        }
    }
}

These methods are called from animateTransition(using:).

The problem is that after the animation ends, in viewController1 cells of the collection view don't appear. I just get the view of the view controller and the collection view itself. I've checked and noticed that lifecycle methods of the view controller don't get called either, however, viewDidLayoutSubviews does get called. Collection view data source methods don't get called, too, so that's why the cells don't appear.

I know I'm missing something quite simple but can't figure out what. I've also checked a few answers here, but none of them helped me.

If you know how to resolve this problem, I would appreciate your help.


Solution

  • After spending some time I finally found a solution. As it is said in Apple's docs, we can't directly call view controller's lifecycle methods (well, we can but it isn't recommended). To call viewController1 lifecycle methods I call beginAppearanceTransition(_:animated:) method from animator:

     toViewController?.beginAppearanceTransition(true, animated: true)
    

    Now, this indeed calls the view controller's lifecycle methods, but the view layout becomes a completely mess (I think, that's because when initially transitioning from the viewController1 I change not only its location but also its scale).

    So, finally I found a solution to that problem, too. To solve it, when transitioning from viewController1, I animate not the view controller itself (its location and scale), but I use its snapshot (the following code is in the animator for transitioning from viewController1 to viewController2):

     let snapshot = UIApplication.shared.keyWindow?.snapshotView(afterScreenUpdates: false)
    

    After having the snapshot, as soon as the transition starts I insert the snapshot into the containerView on top of a viewController1, and remove viewController1 from the superview. Now, I animate the snapshot, which mimics the viewController1.

    This works fine for me. Maybe it will work for someone else.