Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Navigation bar gets adjusted after calling completeTransition: in custom transition

My goal is to provide zooming modal transition from for the user from a view similar as springboard icons zoom in when launching apps.

The presented view controller zooms in correctly, but the navigation bar has wrong position under the status bar. This position gets corrected after calling [transitionContext completeTransition:finished];. How can I make it correct from the beginning of the transition?

This is a screen recording of the bug: http://youtu.be/7LKU4lzb-uw (the glitch is in the 6th second of the recording)

The UIViewControllerAnimatedTransitioning code:

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

    CGPoint viewCenter = self.view.center;
    CGSize viewSize = self.view.frame.size;
    CGSize controllerSize = toViewController.view.frame.size;

    CGFloat controllerFromX = viewCenter.x - (controllerSize.width / 2);
    CGFloat controllerFromY = viewCenter.y - (controllerSize.height / 2);

    CGAffineTransform transform = CGAffineTransformMakeTranslation(controllerFromX, controllerFromY);
    transform = CGAffineTransformScale(transform, viewSize.width / controllerSize.width, viewSize.height / controllerSize.height);

    if (self.reverse) {
        [container insertSubview:toViewController.view belowSubview:fromViewController.view];
    } else {
        toViewController.view.transform = transform;
        [container addSubview:toViewController.view];
    }

    [UIView animateKeyframesWithDuration:ZoomTransitioningDuration 
                                   delay:0 
                                 options:0 
                              animations:^{
                if (self.reverse) {
                    fromViewController.view.alpha = 0.0f;
                    fromViewController.view.transform = transform;
                } else {
                    toViewController.view.transform = CGAffineTransformIdentity;
                }
        } 
                              completion:^(BOOL finished) {
                [transitionContext completeTransition:finished];
        }];
}
like image 692
Ondřej Mirtes Avatar asked Sep 21 '13 19:09

Ondřej Mirtes


2 Answers

The problem is that you are setting the transform before inserting the destination view controller's view into the container.

Switching the order should fix it:

if (self.reverse) {
    [container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
    [container addSubview:toViewController.view];
    toViewController.view.transform = transform;
}

See point 4 here. Since you've applied a transform prior to inserting the navigation controller's view as a subview, the layout engine doesn't think the navigation bar is at the top edge of the window, and therefore doesn't need to be adjusted to avoid the status bar.

like image 134
roperklacks Avatar answered Oct 12 '22 23:10

roperklacks


I've found a solution, although pretty hacky. I have to manually adjust the navigation bar frame before the animation starts:

if (self.reverse) {
    [container insertSubview:toViewController.view belowSubview:fromViewController.view];
} else {
    toViewController.view.transform = transform;
    [container addSubview:toViewController.view];

    // fix navigation bar position to prevent jump when completeTransition: is called
    if ([toViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*) toViewController;
        UINavigationBar* bar = navigationController.navigationBar;
        CGRect frame = bar.frame;
        bar.frame = CGRectMake(frame.origin.x, frame.origin.y + 20.0f, frame.size.width, frame.size.height);
    }
}
like image 22
Ondřej Mirtes Avatar answered Oct 13 '22 01:10

Ondřej Mirtes