这既是一个问题, 部分解决方案。
*示例项目在这里:
https://github.com/JosephLin/TransitionTest
问题1:
当使用transitionFromViewController:...
,在完成布局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:
和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] - [DetailViewController viewWillAppear中:]
TransitionTest [18398:C07] 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:
我认为这是相当多的与调用beginAppearanceTransition:
它修复问题1,但不是问题2加上,医生说不要叫viewWillAppear
直接!
- 使用
[UIView animateWithDuration:]
代替transitionFromViewController:
像这样的:自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