I have implemented a custom transition for a UINavigationController that on presentation will scale the presenting view up and on dismiss will scale view controller being dismissed back down.
I have also implemented percent driven interaction.
I have a strange bug that only occurs in iOS 7.0.* (My app targets 7.0 and above). On certain screens only (but repeatably) if I cancel the percent driven transition by calling cancelInteractiveTransition
on my UIPercentDrivenInteractiveTransition
object, rather than cancelling the transition the top view controller view appears with the properties set in the UIView animation block used by my UIViewControllerContextTransitioning
object for the dismissal animation.
So for example if I set the dismiss animation to scale the dismissing view controller down to 50%, I would see the top view controller scaled to 50% with a black screen behind it, instead of full size as it should be because I have cancelled the transition.
Everything works in iOS 7.1 and above, and on some of the screes in iOS 7.0.
Has anyone seen something like this before or have an idea what the problem might be?
Here is some code:
The implementation of the UINavigationControllerDelegate protocol methods:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
if (UINavigationControllerOperationNone)
{
return nil;
}
if (operation == UINavigationControllerOperationPush)
{
self.transitionAnimator.type = AnimationTypePresent;
return self.transitionAnimator;
}
if (operation == UINavigationControllerOperationPop)
{
self.transitionAnimator.type = AnimationTypeDismiss;
return self.transitionAnimator;
}
return nil;
}
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController
*)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
{
return self.interactionController;
}
The code to begin the interactive transition:
- (void)edgePanGestureBegan:(UIScreenEdgePanGestureRecognizer *)recognizer
{
if (!self.transitionCoordinator) {
self.interactionController = [UIPercentDrivenInteractiveTransition new];
[self popViewControllerAnimated:YES];
}
}
The code to cancel the transition:
[self.interactionController cancelInteractiveTransition];
and the relevant code in my UIViewControllerContextTransitioning
object:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
UIView *containerView = [transitionContext containerView];
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
if (self.type == AnimationTypePresent) {
...
} else if (self.type == AnimationTypeDismiss) {
[containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
[UIView animateWithDuration:[self transitionDuration:transitionContext]
animations:^{
CATransform3D transform = CATransform3DMakeScale(0.01, 0.01, 1.0);
fromViewController.view.layer.transform = transform;
}
completion:^(BOOL finished) {
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
}
}