Панель навигации настраивается после вызова completeTransition: в пользовательском переходе

Моя цель - обеспечить масштабирование модального перехода от пользователя к виду, аналогичному тому, как иконки трамплинов увеличиваются при запуске приложений.

Представленный контроллер просмотра масштабируется правильно, но на панели навигации неправильная позиция находится в строке состояния. Эта позиция исправляется после вызова [transitionContext completeTransition: закончена];. Как я могу сделать это правильно с самого начала перехода?

Это экранная запись ошибки: http://youtu.be/7LKU4lzb-uw (сбой в шестой секунде записи)

Код UIViewControllerAnimatedTransitioning:

- (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];
        }];
}

Ответы

Ответ 1

Проблема заключается в том, что вы устанавливаете преобразование до вставки целевого представления контроллера представления в контейнер.

Переключение порядка должно исправить это:

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

Смотрите пункт 4 здесь. Поскольку вы применили преобразование до вставки представления контроллера навигации в качестве подпредставления, механизм компоновки не считает, что панель навигации находится в верхнем крае окна, и, следовательно, его не нужно настраивать, чтобы избежать строки состояния.

Ответ 2

Я нашел решение, хотя довольно хаки. Мне нужно вручную настроить рамку навигационной панели до начала анимации:

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);
    }
}

Ответ 3

Сначала добавьте toViewControllerView в ContainerView, затем установите преобразование toViewControllerView, как показано ниже.

[контейнер addSubview: toViewController.view];

toViewController.view.transform = transform;

Это решит проблему.

Ответ 4

Это все еще хак, основанный на Ondřej Mirtes ', но он работает лучше, если у вас есть строка состояния в вызове, и вы на iOS8

if([toViewController isKindOfClass:[UINavigationController class]]) { 
  UINavigationController *navCtrl = (UINavigationController *)toViewController;
  UINavigationBar *navBar = navCtrl.navigationBar;
  if(navBar.frame.origin.y == 0 && navBar.frame.size.height == 44) {
    navBar.frame = CGRectMake(0, 0, navBar.frame.size.width, fmin(44 + [UIApplication sharedApplication].statusBarFrame.size.height, 64)); 
  }
}

Остается уродливым, хотя:/