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

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

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

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

Код 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];
        }];
}

4 ответа

Решение

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

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

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

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

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

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

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

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

toViewController.view.transform = transform;

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

Это все еще взлом, основанный на одном из работ Ондржея Миртеса, но он работает лучше, если у вас есть строка состояния во время разговора и вы используете 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)); 
  }
}

Остается безобразным, хотя:/

Другие вопросы по тегам