最近实现的一个需求需要用到模态视图,所以少不了与dismissViewController方法打交道。本文主要讲一讲在使用dismissViewController方法过程中遇到的那些坑。
由于业务逻辑比较特殊,程序中需要在A试图控制器中present B试图控制器的视图,B视图控制器需要present C视图控制器中的视图。最后从C直接返回A。
dismissViewControllerAnimated方法并不难用,其原型为:
- (void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion;
1.flag的含义
flag用与判断知否执行动画(这个很关键,后面会细说)。completion是一个block,用于在dismiss之后执行回调。
我们知道,presentViewController和dismissViewController是一组方法,用于展现和关闭模态视图,而且整个过程的动画是可以完全自定义的。这里的自定义不是像网上有些代码那样,创建一个CATransition对象,设置一堆属性完事,依我愚见,这种只能选择几个固定的系统动画的方式和没有自定义动画没有任何区别!
真正的完全自定义是通过自定义一个动画类来完成。这段代码有点多,等有空总结一下。那么这里的flag对于自定义动画的影响在哪里呢?
答案是如果flag == NO,那么不会执行任何动画(当然也不会执行自定义动画),如果flag == YES,则有可能执行自定义动画,如果没有自定义动画则会执行系统默认动画。
2.dismissViewController在哪里执行
如果由A跳转到B,显然presentViewController方法应该在A里面执行,那么当我们希望关闭模态视图B时,dismissViewController在哪里执行呢?
标准答案是:在A视图控制器里执行,这里只要简单的记住一个原则既可:
谁污染,谁治理!
这是和pushViewController和popViewController那一组方法不同的地方。
不过在B视图中执行也是可以的,因为系统会自动优化,当B视图控制器没有present过其他视图控制器的时候,dismissViewController方法会自动交给B的presentingViewController执行,也就是A视图。
不过处于严谨性考虑,还是应该在A视图控制器中执行dismissViewController方法。
3.多个模态视图之间跳转
正如此前所说,需要从视图C直接返回视图A。在网上也看到一些解答,比如说利用通知让B试图控制器执行dismissViewController方法。其实这样是不行的,原因刚刚已经解释过,对于一个视图控制器X,它执行dismissViewController方法的时候将会关闭它present的模态视图,只有在它没有present过模态视图的时候,才会交给他的presentingViewController执行dismissViewController方法。所以这里如果交给B执行,和直接在C里面执行dismissViewController方法的效果是一样的。
显然一个最简单的解决办法就是利用通知或者代理,在A中执行dismissViewController方法。这里已经成功了一半,因为dismissViewController总是要在A方法中执行的。不过这样做会遇到两个问题:
1.代码耦合
2.用户体验
这里的代码耦合指的是,我们应该尽量避免代理或者通知的使用,比如这时候A视图控制器换成了A’ 那么A’在不修改任何代码的时候肯定是无法直接放在整个项目里面使用的。此时要么重新实现协议,要么监听通知。
所谓的用户体验是指,在A中执行dismissViewController方法时,会依次关闭模态视图。模态视图的关闭是被关闭的视图从原来父视图上向下滑动直到滑出父视图。所以用户会看到两个过程:
- 视图控制器C的视图从试图控制器B的视图上向下滑出
- 视图控制器B的视图从试图控制器A的视图上向下滑出
而我相信,绝大部分的需求是“视图控制器C的视图从试图控制器A的视图上向下滑出”。
其实解决办法很简单:
self.presentingViewController.view.alpha = 0;
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
只用两行代码就可以比较完美的解决问题。第一行代码让B的视图变为透明(由于父视图变为透明,任何B的子视图都会透明)。这样的效果将是C的视图从A的视图上滑出。
第二行代码中连续获取了两次presentingViewController,其实就是A,不过这使得A视图控制器中不用添加任何代码,从而解决了耦合的问题。
这样写的另一个好处是,不管是多少个视图控制器之间的跳转,都可以很方便的完成。
当然通过自定义动画,也可以只用一行dismissViewController方法解决问题。等有空会单独写一篇关于自定义视图跳转动画的博客。
版权声明:本文为博主原创文章,未经博主允许不得转载。