dismissViewController实现多个模态视图跳转

最近实现的一个需求需要用到模态视图,所以少不了与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方法时,会依次关闭模态视图。模态视图的关闭是被关闭的视图从原来父视图上向下滑动直到滑出父视图。所以用户会看到两个过程:

  1. 视图控制器C的视图从试图控制器B的视图上向下滑出
  2. 视图控制器B的视图从试图控制器A的视图上向下滑出

而我相信,绝大部分的需求是“视图控制器C的视图从试图控制器A的视图上向下滑出”。

其实解决办法很简单:

self.presentingViewController.view.alpha = 0;
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];

只用两行代码就可以比较完美的解决问题。第一行代码让B的视图变为透明(由于父视图变为透明,任何B的子视图都会透明)。这样的效果将是C的视图从A的视图上滑出。

第二行代码中连续获取了两次presentingViewController,其实就是A,不过这使得A视图控制器中不用添加任何代码,从而解决了耦合的问题。

这样写的另一个好处是,不管是多少个视图控制器之间的跳转,都可以很方便的完成。

当然通过自定义动画,也可以只用一行dismissViewController方法解决问题。等有空会单独写一篇关于自定义视图跳转动画的博客。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 08:36:09

dismissViewController实现多个模态视图跳转的相关文章

视图控制器、模态视图

一.什么是试图控制器? 视图控制器就是用来管理视图的加载.卸载.横屏竖屏显示等操作的控制器. 每一个界面都会由一个控制器来管理显示 ,单独的界面view需要视图控制器这个载体来管理显示. UIViewController是所有视图控制器的父类 . iOS提供了许多内置的视图控制器类,以支持标准的用户界面部分,比如导航控制器 (UINavigationController),标签栏控制器(UITabBarController),表视图控制器 (UITableViewController)等 . 每

视图控制器和导航模式一(模态视图,平铺导航)

视图控制器的种类 UIViewController.用于自定义视图控制器的导航.例如,对于两个界面的跳转,我们可以用一个UIViewController来控制另外两个UIViewController. UINavigationController.导航控制器,它与UITableViewController结合使用,能够构建树形结构导航模式. UITabBarController.标签栏控制器,用于构建树标签导航模式. UIPageViewController.呈现电子书导航风格的控制器 UISp

iOS开发 - 在SwiftUI中显示模态视图

在SwiftUI中显示模态视图 简介 这里教大家如何弹出一个简单的模态视图.分别有两个页面,ContentView和GCPresentedView,以下对应简称为A和B.我们要做的是在A视图中点击按钮跳转到B视图,然后再从B视图点击按钮返回到A视图. 步骤 在A视图中创建按钮和模态视图代码 struct ContentView: View { @State var isPresented = false var body: some View { Button(action: { self.is

UI03-viewController 视图跳转:

/*  ******今日任务:登陆界面 进行最后的优化 ,封装控件 (2)viewController (3)MVC 思想(4)对于屏幕旋转,内存异常的处理,(5)容器视图控制器,四个方法的使用 视图切换的方式 1.登陆界面的优化, (1)封装的设计模式的,组合类模式的装饰者模式,复合设计模式,23种设计模式    一个自定义控件里面有多个系统控件, (1)自定义一个视图,基于UI view,把包含的系统控件作为.h里的属性, (2)在.m中重写初始化方法,把各个系统控件的属性写死,注意各个控件

0527.模态视图的概念以及显示、变换方式介绍

学几个单词 dissolve  [d?'z?lv] vi. 溶解:解散 curl  [k??l]  vi. 卷曲 什么是模态视图? 比如UIAlertView,它就是一个模态视图.对于模态视图和普通视图最主要的区别就是模态视图显示的时候不能对其他视图进行操作.主要用来收集或显示一些信息. 思考:弹出警告框的时候,背景视图变暗不能操作,所以说警告框就是一个模态视图. Presentation Style(显示方式) 对于iPhone来讲Presentation Style始终是UIModalPre

iOS 利用模态视图实现带黑色蒙版的底部弹窗

本demo仅适用于iOS8及以上系统. 本文将使用autolayout+storyboard来实现弹窗 第一步.storyboard创建界面 1.打开storyboard 拖一个UIViewcontroller出来,并与class相关联 2.拖出一个UIView作为弹窗视图的容器,容器里放置弹窗的内容,容器高度根据具体需求放置.容器放在最底部 3.放置一个UIButton在容器View的上方间距为0,并把UIButton设置为黑色(用于实现蒙版效果及点击空白处关闭弹窗) 4.约束.底部容器打le

通知模式实现两个textField传值及模态视图——iOS开发

通知模式实现两个textField传值及模态视图--iOS开发 利用通知模式,实现两个不同界面的textField之间的传值,在界面二输入字符,传值到前一界面的textField. 界面的切换,这里临时先用模态视图实现.(重点在传值.所以没纠结设计界面排版.丑了点大家见谅) 大家不要看代码看上去好像挺多.由于我没使用storyboard/xib,是代码实现布局,所以通知和模态视图切换的代码非常少~ 实现效果: 点击下一页按钮,进入界面二: 在textField处输入字符串: 点击返回按钮,回到界

Swfit中视图跳转

1.跳转到任一UIViewController var sb = UIStoryboard(name: "Main", bundle:nil) var vc = sb.instantiateViewControllerWithIdentifier("ChooseViewController") as ChooseViewController self.presentViewController(vc, animated:true, completion:nil) 2

FormSheet式模态视图,点击模态视图外隐藏模态视图的方法

#pragma -mark 点击模态视图外的空白处隐藏模态视图 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapBehind:)]; [_tapRecognizer setNumberOfTapsRequired:1