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.