Search code examples
iosios7

Custom transition animation not calling VC lifecycle methods on dismiss


So I built a custom presenting transition animation and everything seems to be working great except the view controller lifecycle methods are not being called on dismiss.

Before presenting the controller I use the UIModalPresentationCustom style to keep the presenting VC in the view hierarchy, but once I dismiss the presented VC, viewWillAppear and viewDidAppear are not called on my presenting controller. Am I missing a step that I need to explicitly call to get those methods to fire? I know manually calling those methods is not the correct solution.

Here is my dismissing animation code. I'm basically animating a form overlay view to shrink to the size of a collection view cell on dismissal.

- (void)_animateDismissingTransitionWithContext:(id<UIViewControllerContextTransitioning>)transitionContext
{
    UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    UICollectionView *destinationCollectionView = toCollectionViewController.collectionView;
    UICollectionViewCell *destinationCollectionViewCell = [self _destinationCellFromContext:transitionContext];
    UIView *containerView = transitionContext.containerView;

    // Calculate frames    
    CGRect startFrame = fromEventDetailViewController.detailContainerView.frame;
    CGRect endFrame = [destinationCollectionView convertRect:destinationCollectionViewCell.frame toView:containerView];

    // Add overlay
    UIView *overlayView = [UIView new];
    overlayView.backgroundColor = [UIColor overlayBackground];
    overlayView.frame = containerView.bounds;
    overlayView.alpha = 1.0f;
    [containerView addSubview:overlayView];

    // Add fake detail container view
    UIView *fakeContainerView = [UIView new];
    fakeContainerView.backgroundColor = fromEventDetailViewController.detailContainerView.backgroundColor;
    fakeContainerView.frame = startFrame;
    [containerView addSubview:fakeContainerView];

    // Hide from view controller
    fromEventDetailViewController.view.alpha = 0.0f;

    [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0f usingSpringWithDamping:0.75f initialSpringVelocity:0.2f options:UIViewAnimationOptionCurveEaseOut animations:^{
        fakeContainerView.frame = endFrame;
        fakeContainerView.backgroundColor = [UIColor eventCellBackground];

        overlayView.alpha = 0.0f;
    } completion:^(BOOL finished) {
        [fromEventDetailViewController.view removeFromSuperview];
        [overlayView removeFromSuperview];
        [fakeContainerView removeFromSuperview];

        [transitionContext completeTransition:YES];
    }];
}

Solution

  • Another solution could be using beginAppearanceTransition: and endAppearanceTransition:. According to documentation:

    If you are implementing a custom container controller, use this method to tell the child that its views are about to appear or disappear. Do not invoke viewWillAppear:, viewWillDisappear:, viewDidAppear:, or viewDidDisappear: directly.

    Here is how I used them:

    - (void)animationEnded:(BOOL)transitionCompleted
    {
        if (!transitionCompleted)
        {
            _toViewController.view.transform = CGAffineTransformIdentity;
        }
        else
        {
            [_toViewController endAppearanceTransition];
        }
    }
    
    - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
        [toViewController beginAppearanceTransition:YES animated:YES];
        // ... other code
    }
    

    But I still consider strange that custom modal presentation not doing this.