iOS中显示ViewController的方式有两种push和modal,modal也叫模态,模态显示VC是iOS的重要特性之一,其主要用于有如下场景objective-c
这些场景都会暂时中断APP的正常执行流程,主要做用是收集信息以及显示一些重要的提示等。swift
当vcA模态的弹出了vcB,那么vcA就是presenting view controller,vcB就是presented view controller,具体在代码中体现以下:ide
vcA.present(vcB, animated: true, completion: nil)
函数
container view controller 指的是VC的容器类,经过container view controller,咱们能够很方便的管理子VC,实现VC之间的跳转等,iOS中container view controller包括NavigationController, UISplitViewController, 以及 UIPageViewController.动画
presented VC 的modalPresentationStyle属性决定了这次presentation的行为方式及UIKit寻找presentation context的方法,iOS提供了如下几种经常使用的presentation style:ui
UIKit默认的presentation style。 使用这种模式时,presented VC的宽高与屏幕相同,而且UIKit会直接使用rootViewController作为presentation context,在这次presentation完成以后,UIKit会将presentation context及其子VC都移出UI栈,这时候观察VC的层级关系,会发现UIWindow下只有presented VC.url
在常规型设备(大屏手机,例如plus系列以及iPad系列)的水平方向,presented VC的高为当前屏幕的高度,宽为该设备竖直方向屏幕的宽度,其他部分用透明背景作填充。对于紧凑型设备(小屏手机)的水平方向及全部设备的竖直方向,其显示效果与UIModalPresentationFullScreen相同。spa
在常规型设备的水平方向,presented VC的宽高均小于屏幕尺寸,其他部分用透明背景填充。对于紧凑型设备的水平方向及全部设备的竖直方向,其显示效果与UIModalPresentationFullScreen相同3d
使用这种方式present VC时,presented VC的宽高取决于presentation context的宽高,而且UIKit会寻找属性definesPresentationContext为YES的VC做为presentation context,具体的寻找方式会在下文中给出 。当这次presentation完成以后,presentation context及其子VC都将被暂时移出当前的UI栈。rest
自定义模式,须要实现UIViewControllerTransitioningDelegate的相关方法,并将presented VC的transitioningDelegate 设置为实现了UIViewControllerTransitioningDelegate协议的对象。
与UIModalPresentationFullScreen的惟一区别在于,UIWindow下除了presented VC,还有其余正常的VC层级关系。也就是说该模式下,UIKit以rootViewController为presentation context,但presentation完成以后不会讲rootViewController移出当前的UI栈。
寻找presentation context的方式与UIModalPresentationCurrentContext相同,所不一样的是presentation完成以后,不会将context及其子VC移出当前UI栈。可是,这种方式只适用于transition style为UIModalTransitionStyleCoverVertical的状况(UIKit默认就是这种transition style)。其余transition style下使用这种方式将会触发异常。
presentation完成以后,若是presented VC的背景有透明部分,会看到presented VC下面的VC会变得模糊,其余与UIModalPresentationOverFullScreen模式没有区别。
present VC是经过UIViewController的presentViewController: animated:completion: 函数实现的,在探讨他们之间的层级关系以前,咱们首先要理解一个概念,就是presentation context。
presentation context是指为本次present提供上下文环境的类,须要指出的是,presenting VC一般并非presentation context,Apple官方文档对于presentation context的选择是这样介绍的:
When you present a view controller, UIKit looks for a view controller that provides a suitable context for the presentation. In many cases, UIKit chooses the nearest container view controller but it might also choose the window’s root view controller. In some cases, you can also tell UIKit which view controller defines the presentation context and should handle the presentation.
从上面的介绍能够看出,当咱们须要present VC的时候,除非咱们指定了context,不然UIKit会优先选择presenting VC所属的容器类作为presentation context,若是没有容器类,那么会选择rootViewController。可是,UIKit搜索context的方式还与presented VC的modalPresentationStyle属性有关,当modalPresentationStyle为UIModalPresentationFullScreen、UIModalPresentationOverFullScreen等模式时,UIKit会直接选择rootViewController作为context。当modalPresentationStyle为UIModalPresentationOverCurrentContext、UIModalPresentationCurrentContext模式时,UIKit搜索context的方式以下:
UIModalPresentationOverCurrentContext、UIModalPresentationCurrentContext模式下,一个VC可否成为presentation context 是由VC的definesPresentationContext属性决定的,这是一个BOOL值,默认UIViewController的definesPresentationContext属性值是NO,而 container view controller的definesPresentationContext默认值是YES,这也是上文中,UIKit老是将container view controller作为presentation context的缘由。若是咱们想指定presenting VC作为context,只须要在presenting VC的viewDidLoad方法里添加以下代码便可:
self.definesPresentationContext = YES
复制代码
UIKit搜索presentation context的顺序为:
还有另一种特殊状况,当咱们在一个presented VC上再present一个VC时,UIKit会直接将这个presented VC作为presentation context。
在iOS 中,presented VC 老是与 presentation context 处于同一层级,而与presenting VC所在的层级无关,且同一个presentation context同时只能有一个presented VC。
下面咱们经过代码来验证这个结论。首先新建一个APP,各VC之间的层级关系以下:
在SecondContentVC中present FirstPresentVC,代码以下:
FirstPresentVC *vc = [[FirstPresentVC alloc] init];
vc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:vc animated:YES completion:nil];
复制代码
为了更好的观察各VC的层级关系,咱们将presented VC 的modalPresentationStyle属性设置为UIModalPresentationOverCurrentContext,而后咱们再看各VC之间的层级关系:
能够看到FirstPresentVC 与 SecondContentVC的navigationViewController处在同一层级,说明这时的presentation context是navigationViewController。下面咱们在FirstContentVC的viewDidLoad方法里添加以下代码:
self.definesPresentationContext = YES;
复制代码
弹出FirstPresentVC后再看VC之间的层级关系:
能够看到,FirstPresentVC 与 FirstContentVC 处在同一层级,说明此时的presentation context为FirstContentVC.
下面咱们将SecondContentVC的definesPresentationContext属性设为YES,而后观察弹出FirstPresentVC以后的层级关系:
modalTransitionStyle能够设置presentation的转场动画,官方提供了几种不一样的转场动画,默认是UIModalTransitionStyleCoverVertical。若是想要使用别的style,只须要设置presented VC的modalTransitionStyle属性便可。其他三种包括:
具体每种style的表现形式参考Demo.