最近项目中遇到一个很奇怪的问题,项目的主控制器导航栏需要隐藏,从主控制器Push出来的控制器中的导航栏都要显示。
结果有一天,闲来无事,从主控制器Push出来一个控制器之后,就把push出来的控制器往右滑(导航控制器关闭一个控制器的手势),然后在这个Push出来的控制器快消失的时候,又把它复原,结果,再Push控制器的时候,导航栏的标题和返回按钮全都乱了。如下图

后来在Stack Overflow上看到了一个很不错的解决方法:
首先,导航控制器的pop手势操作其实也是一种动画,当用手势操作导航控制器pop的时候,其实我们看到的是动画执行的过程而已,只是动画和我们的手势同步而已。当pop手势取消的时候,系统会决定该动画是rollBack还是一直执行到end。
接下来,就是上面现象产生的原因了
1.这是解决方法一:注意到测试工程里面隐藏导航栏是写在viewWillAppear里面的,问题就在这里。
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES];
}
当pop手势执行的时候,第一个控制器的viewWillAppear就开始执行了。根据苹果的解释,"view will appear" actually means "view might appear". 意思已经很明显了,我们更应该把隐藏导航栏的代码放到viewDidApear里面去,因为只有pop手势结束的时候才会执行viewDidApear.
2.解决方法二:导航栏标题和返回按钮变乱的根本原因是什么呢?
这里隐藏着第二种动画,所有和导航栏相关的(比如title, 比如返回按钮)。运行时会自己来决定这个动画该怎么执行。但是测试工程中我是没有使用动画的。所以,我们应该使用动画而不是取消动画导致最终效果不协调。
[self.navigationController setNavigationBarHidden:YES animated:YES];
3.解决方法三: 但是,有时候上面两种解决方法并不是正确的解决姿势,比如我的项目中就不太适合第一种解决方式。所以,最终的解决方法来了:
系统专门提供了一个动画过渡协调类来解决这个问题_,我们可以使用这个类来处理上面动画取消或完成时的动作。(把第一个控制器的viewWillAppear改写如下即可了)
-(void)viewWillAppear:(BOOL)animated{
[superview WillAppear:animated];
id<UIViewControllerTransitionCoordinator> tc =self.transitionCoordinator;
if(tc && [tc initiallyInteractive]) {
[tc notifyWhenInteractionEndsUsingBlock:
^(id<UIViewControllerTransitionCoordinatorContext> context) {
if([context isCancelled]) {
// do nothing!
}else{// not cancelled, do it
[self.navigationController setNavigationBarHidden:YESanimated:NO];
}
}];
}else{// not interactive, do it
[self.navigationController setNavigationBarHidden:YESanimated:NO];
}
}
感谢万能的Stack Overflow.
网友评论