Контроллер пользовательского контейнера: transitionFromViewController: представление неправильно выложено перед анимацией

Это и вопрос, ичастичный решение.

* Пример проекта здесь:

https://github.com/JosephLin/TransitionTest

Проблема 1:

Когда используешьtransitionFromViewController:...макеты сделаныtoViewController«sviewWillAppear: не отображается, когда начинается анимация перехода. Другими словами, представление перед макетом отображается во время анимации, и его содержимое привязывается к позициям после макета после анимации.

Проблема 2:

Если я настрою фон моего navbar'sUIBarButtonItemкнопка бара отображается с неверным размером / положением перед анимацией и привязывается к правильному размеру / положению после завершения анимации, как в случае с проблемой 1.

Чтобы продемонстрировать проблему, я сделал собственный контейнерный контроллер, который выполняет некоторые пользовательские переходы представления. Это в значительной степени копия UINavigationController, которая выполняет перекрестное растворение вместо анимации push между представлениями.

Метод «Push» выглядит следующим образом:

- (void)pushController:(UIViewController *)toViewController
{
    UIViewController *fromViewController = [self.childViewControllers lastObject];

    [self addChildViewController:toViewController];
    toViewController.view.frame = self.view.bounds;

    NSLog(@"Before transitionFromViewController:");
    [self transitionFromViewController:fromViewController
                      toViewController:toViewController
                              duration:0.5
                               options:UIViewAnimationOptionTransitionCrossDissolve
                            animations:^{}
                            completion:^(BOOL finished) {
                                [toViewController didMoveToParentViewController:self];
                            }];
}

В настоящее время,DetailViewController (контроллер представления, к которому я обращаюсь) должен расположить содержимое вviewWillAppear:, Это не может сделать это вviewDidLoad потому что у него не было бы правильного кадра в то время.

Для демонстрации,DetailViewController устанавливает свою метку в разных местах и цветах вviewDidLoad, viewWillAppear, а такжеviewDidAppear:

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"%s", __PRETTY_FUNCTION__);
    CGRect rect = self.descriptionLabel.frame;
    rect.origin.y = 50;
    self.descriptionLabel.frame = rect;
    self.descriptionLabel.text = @"viewDidLoad";
    self.descriptionLabel.backgroundColor = [UIColor redColor];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    NSLog(@"%s", __PRETTY_FUNCTION__);
    CGRect rect = self.descriptionLabel.frame;
    rect.origin.y = 200;
    self.descriptionLabel.frame = rect;
    self.descriptionLabel.text = @"viewWillAppear";
    self.descriptionLabel.backgroundColor = [UIColor yellowColor];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSLog(@"%s", __PRETTY_FUNCTION__);
    CGRect rect = self.descriptionLabel.frame;
    rect.origin.y = 350;
    self.descriptionLabel.frame = rect;
    self.descriptionLabel.text = @"viewDidAppear";
    self.descriptionLabel.backgroundColor = [UIColor greenColor];
}

Теперь при нажатииDetailViewControllerЯ ожидаю увидеть ярлык наy =200 в начале анимации (левое изображение), а затем переходит кy = 350 после окончания анимации (правое изображение).

Ожидаемый вид до и после анимации.

Тем не менее, этикетка была наy=50, как будто макет сделан вviewWillAppear не сделал это до того, как произошла анимация (левое изображение). Но обратите внимание, что фон метки был установлен на желтый (цвет, указанныйviewWillAppear)!

Неправильный макет в начале анимации. Обратите внимание, что кнопки панели также начинаются с неправильной позиции / размера.

Console Log
TransitionTest [49795: c07] - [DetailViewController viewDidLoad]
TransitionTest [49795: c07] Перед transitionFromViewController:
TransitionTest [49795: c07] - [DetailViewController viewWillAppear:]
TransitionTest [49795: c07] - [DetailViewController viewWillLayoutSubviews]
TransitionTest [49795: c07] - [DetailViewController viewDidLayoutSubviews]
TransitionTest [49795: c07] - [DetailViewController viewDidAppear:]
Заметить, чтоviewWillAppear: называлсяПОСЛЕ transitionFromViewController:

Решение проблемы 1

Хорошо, вот идетчастичный часть решения. Явным вызовомbeginAppearanceTransition: а такжеendAppearanceTransition вtoViewControllerвид будет иметь правильную компоновку до анимации перехода:

- (void)pushController:(UIViewController *)toViewController
{
    UIViewController *fromViewController = [self.childViewControllers lastObject];

    [self addChildViewController:toViewController];
    toViewController.view.frame = self.view.bounds;

    [toViewController beginAppearanceTransition:YES animated:NO];

    NSLog(@"Before transitionFromViewController:");
    [self transitionFromViewController:fromViewController
                      toViewController:toViewController
                              duration:0.5
                               options:UIViewAnimationOptionTransitionCrossDissolve
                            animations:^{}
                            completion:^(BOOL finished) {
                                [toViewController didMoveToParentViewController:self];
                                [toViewController endAppearanceTransition];
                            }];
}

Заметить, чтоviewWillAppear: теперь называется ДОtransitionFromViewController: TransitionTest [18398: c07] - [DetailViewController viewDidLoad]
TransitionTest [18398: c07] - [Представление DetailViewControllerWillAppear:]
TransitionTest [18398: c07] Перед transitionFromViewController:
TransitionTest [18398: c07] - [Представление DetailViewControllerWillLayoutSubviews]
TransitionTest [18398: c07] - [DetailViewController viewDidLayoutSubviews]
TransitionTest [18398: c07] - [DetailViewController viewDidAppear:]

Но это не решает проблему 2!

По любой причине кнопки навигационной панели по-прежнему начинаются с неправильной позиции / размера в начале анимации перехода. Я потратил так много времени, пытаясь найти правильное решение, но без удачи. Я начинаю чувствовать, что это ошибка вtransitionFromViewController: или жеUIAppearance или что угодно. Пожалуйста, любые идеи, которые вы можете предложить по этому вопросу, с благодарностью. Спасибо!

Другие решения, которые я пробовал

Вызов[self.view addSubview:toViewController.view]; доtransitionFromViewController:

Это на самом деле дает правильный результат пользователю, устраняет проблемы 1 и 2. Проблема в,viewWillAppear а такжеviewDidAppear оба будут вызваны дважды! Это проблематично, если я хочу сделать некоторую обширную анимацию или расчет вviewDidAppear.

Вызов[toViewController viewWillAppear:YES]; доtransitionFromViewController:

Я думаю, что это почти так же, как звонитьbeginAppearanceTransition:, Это решает проблему 1, но не проблему 2. Кроме того, док говорит не звонитьviewWillAppear напрямую!

использование[UIView animateWithDuration:] вместоtransitionFromViewController:

Вот так: [self addChildViewController: toViewController]; [self.view addSubview: toViewController.view]; toViewController.view.alpha = 0.0;

[UIView animateWithDuration:0.5 animations:^{
    toViewController.view.alpha = 1.0;
} completion:^(BOOL finished) {
    [toViewController didMoveToParentViewController:self];
}];

Это решает проблему 2, но представление началось с макета вviewDidAppear (метка зеленая, у = 350). Кроме того, перекрестное растворение не так хорошо, как при использованииUIViewAnimationOptionTransitionCrossDissolve

Ответы на вопрос(2)

Ваш ответ на вопрос