这既是一个问题,也是部分解决方案。
*这里的示例项目:
https://github.com/JosephLin/TransitionTest
问题1:
使用 时,由'stransitionFromViewController:...
完成的布局不会在过渡动画开始时显示。换句话说,预布局视图在动画期间显示,并且它的内容在动画之后捕捉到布局后位置。toViewController
viewWillAppear:
问题2:
如果我自定义导航栏的背景UIBarButtonItem
,则栏按钮在动画前以错误的大小/位置显示,并在动画结束时捕捉到正确的大小/位置,类似于问题 1。
为了演示这个问题,我制作了一个简单的自定义容器控制器,它可以进行一些自定义视图转换。它几乎是一个 UINavigationController 副本,它确实交叉溶解而不是在视图之间推送动画。
“推送”方法如下所示:
- (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
)!
动画开头的布局错误。请注意,条形按钮也以错误的位置/大小开始。
控制台日志
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:
and 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:
现在称为 BEFOREtransitionFromViewController:
TransitionTest[18398:c07] -[DetailViewController viewDidLoad]
TransitionTest[18398:c07] -[DetailViewController viewWillAppear:]
TransitionTest[18398:c07] Before transitionFromViewController:
TransitionTest[18398:c07] -[DetailViewController viewWillLayoutSubviews]
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:
我认为这与 call 几乎相同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
(标签为绿色,y=350)。此外,交叉溶解不如使用UIViewAnimationOptionTransitionCrossDissolve