Jos*_*Lin 24 xcode uiviewcontroller ios uiappearance
这既是一个问题,也是一个部分解决方案.
*示例项目:
https://github.com/JosephLin/TransitionTest
使用时,过渡动画开始时,不会显示transitionFromViewController:...由toViewControllers 完成的布局viewWillAppear:.换句话说,预布局视图在动画期间显示,并且其内容在动画之后捕捉到布局后位置.
如果我自定义导航栏的背景UIBarButtonItem,则条形按钮会在动画播放前显示错误的大小/位置,并在动画结束时捕捉到正确的大小/位置,类似于问题1.
为了演示这个问题,我做了一个裸骨的自定义容器控制器来执行一些自定义视图转换.它几乎是一个UINavigationController副本,它在视图之间进行交叉消解而不是推送动画.
'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];
}];
}
Run Code Online (Sandbox Code Playgroud)
现在,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];
}
Run Code Online (Sandbox Code Playgroud)
现在,当推动时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:名为AFTER 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];
}];
}
Run Code Online (Sandbox Code Playgroud)
请注意,viewWillAppear:现在称为BEFOREtransitionFromViewController:
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:]
无论出于何种原因,导航按钮仍然在过渡动画开始时以错误的位置/大小开始.我花了很多时间试图找到正确的解决方案,但没有运气.我开始觉得这是在一个错误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];
}];
Run Code Online (Sandbox Code Playgroud)
它修复了问题2,但视图以布局开始viewDidAppear(标签为绿色,y = 350).此外,交叉溶解不如使用UIViewAnimationOptionTransitionCrossDissolve
好吧,添加layoutIfNeeded到toViewController.view似乎可以做到这一点 - 这会在视图显示在屏幕上之前正确显示视图(没有添加/删除),并且没有更奇怪的双viewDidAppear:call.
- (void)pushController:(UIViewController *)toViewController
{
UIViewController *fromViewController = [self.childViewControllers lastObject];
[self addChildViewController:toViewController];
toViewController.view.frame = self.view.bounds;
[toViewController.view layoutIfNeeded];
NSLog(@"Before transitionFromViewController:");
[self transitionFromViewController:fromViewController
toViewController:toViewController
duration:0.5
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{}
completion:^(BOOL finished) {
}];
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9089 次 |
| 最近记录: |