Контроллер пользовательского контейнера: transitionFromViewController: представление неправильно выложено перед анимацией
Это и вопрос, ичастичный решение.
* Пример проекта здесь:
https://github.com/JosephLin/TransitionTest
Проблема 1:Когда используешьtransitionFromViewController:...
макеты сделаныtoViewController
«sviewWillAppear:
не отображается, когда начинается анимация перехода. Другими словами, представление перед макетом отображается во время анимации, и его содержимое привязывается к позициям после макета после анимации.
Если я настрою фон моего 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:
Хорошо, вот идетчастичный часть решения. Явным вызовом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:]
По любой причине кнопки навигационной панели по-прежнему начинаются с неправильной позиции / размера в начале анимации перехода. Я потратил так много времени, пытаясь найти правильное решение, но без удачи. Я начинаю чувствовать, что это ошибка в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