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]; }]; }
Calling the completeTransition: method at the end of your animations is required. UIKit does not end the transition process, and thereby return control to your app, until you call that method.
A transition animation swaps the contents of one view controller for the contents of another. There are two types of transitions: presentations and dismissals. A presentation transition adds a new view controller to your app’s view controller hierarchy, whereas a dismissal transition removes one or more view controllers from the hierarchy.
At the end of a transition animation, it is critical that you call the completeTransition: method. Calling that method tells UIKit that the transition is complete and that the user may begin to use the presented view controller.
Aside from the presentation and dismissal of a view controller, transitions can occur when an interface rotation occurs or when the frame of a view controller changes. All of these transitions represent changes to the view hierarchy.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With