Swift - 詳解iOS的presentViewController

一、用途和相關概念
iOS中顯示ViewController的方式有兩種push和modal,modal也叫模態,模態顯示VC是iOS的重要特性之一,其主要用於有以下場景:

  • 收集用戶輸入信息
  • 臨時呈現一些內容
  • 臨時改變工作模式
  • 相應設備方向變化(用於針對不同方向分別是想兩個ViewController的情況)
  • 顯示一個新的view層級

這些場景都會暫時中斷APP的正常執行流程,主要作用是收集信息以及顯示一些重要的提示等。

presenting view controller & presented view controller
當VCA模態的彈出了VCB,那麼VCA就是presenting view controller,VCB就是presented view controller,具體在代碼中體現如下:

[VCA presentViewController:VCB animated:YES completion:nil];
1
container view controller
container view controller 指的是VC的容器類,通過container view controller,我們可以很方便的管理子VC,實現VC之間的跳轉等,iOS中container view controller包括g UINavigationController, UISplitViewController, 以及 UIPageViewController.

二、ModalPresentationStyle & Presentation Context
ModalPresentationStyle
presented VC 的modalPresentationStyle屬性決定了此次presentation的行爲方式及UIKit尋找presentation context的方法,iOS提供了以下幾種常用的presentation style:

UIModalPresentationFullScreen

UIKit默認的presentation style。 使用這種模式時,presented VC的寬高與屏幕相同,並且UIKit會直接使用rootViewController做爲presentation context,在此次presentation完成之後,UIKit會將presentation context及其子VC都移出UI棧,這時候觀察VC的層級關係,會發現UIWindow下只有presented VC.

UIModalPresentationPageSheet

在常規型設備(大屏手機,例如plus系列以及iPad系列)的水平方向,presented VC的高爲當前屏幕的高度,寬爲該設備豎直方向屏幕的寬度,其餘部分用透明背景做填充。對於緊湊型設備(小屏手機)的水平方向及所有設備的豎直方向,其顯示效果與UIModalPresentationFullScreen相同。

UIModalPresentationFormSheet

在常規型設備的水平方向,presented VC的寬高均小於屏幕尺寸,其餘部分用透明背景填充。對於緊湊型設備的水平方向及所有設備的豎直方向,其顯示效果與UIModalPresentationFullScreen相同

UIModalPresentationCurrentContext

使用這種方式present VC時,presented VC的寬高取決於presentation context的寬高,並且UIKit會尋找屬性definesPresentationContext爲YES的VC作爲presentation context,具體的尋找方式會在下文中給出 。當此次presentation完成之後,presentation context及其子VC都將被暫時移出當前的UI棧。

UIModalPresentationCustom

自定義模式,需要實現UIViewControllerTransitioningDelegate的相關方法,並將presented VC的transitioningDelegate 設置爲實現了UIViewControllerTransitioningDelegate協議的對象。

UIModalPresentationOverFullScreen

與UIModalPresentationFullScreen的唯一區別在於,UIWindow下除了presented VC,還有其他正常的VC層級關係。也就是說該模式下,UIKit以rootViewController爲presentation context,但presentation完成之後不會講rootViewController移出當前的UI棧。

UIModalPresentationOverCurrentContext

尋找presentation context的方式與UIModalPresentationCurrentContext相同,所不同的是presentation完成之後,不會將context及其子VC移出當前UI棧。但是,這種方式只適用於transition style爲UIModalTransitionStyleCoverVertical的情況(UIKit默認就是這種transition style)。其他transition style下使用這種方式將會觸發異常。

UIModalPresentationBlurOverFullScreen

presentation完成之後,如果presented VC的背景有透明部分,會看到presented VC下面的VC會變得模糊,其他與UIModalPresentationOverFullScreen模式沒有區別。

present VC是通過UIViewController的presentViewController: animated:completion:
函數實現的,在探討他們之間的層級關係之前,我們首先要理解一個概念,就是presentation context。

  • 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.
1
從上面的介紹可以看出,當我們需要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
1
UIKit搜索presentation context的順序爲:

  1. presenting VC
  2. presenting VC 的父VC
  3. presenting VC 所屬的container VC
  4. rootViewController

還有另外一種特殊情況,當我們在一個presented VC上再present一個VC時,UIKit會直接將這個presented VC做爲presentation context。

三、presenting VC 與presented VC 之間的層級關係
在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];
1
2
3
爲了更好的觀察各VC的層級關係,我們將presented VC 的modalPresentationStyle屬性設置爲UIModalPresentationOverCurrentContext,這。然後我們再看各VC之間的層級關係:

可以看到FirstPresentVC 與 SecondContentVC的navigationViewController處在同一層級,說明這時的presentation context是navigationViewController。下面我們在FirstContentVC的viewDidLoad方法裏添加如下代碼:

self.definesPresentationContext = YES;
1
彈出FirstPresentVC後再看VC之間的層級關係:

可以看到,FirstPresentVC 與 FirstContentVC 處在同一層級,說明此時的presentation context爲FirstContentVC.

下面我們將SecondContentVC的definesPresentationContext屬性設爲YES,然後觀察彈出FirstPresentVC之後的層級關係:

可以看到,此時的presentation context爲SecondContentVC。這個實驗也驗證了UIKit 搜索presentation context的順序。

四、ModalTransitionStyle
modalTransitionStyle可以設置presentation的轉場動畫,官方提供了幾種不同的轉場動畫,默認是UIModalTransitionStyleCoverVertical。如果想要使用別的style,只需要設置presented VC的modalTransitionStyle屬性即可。其餘三種包括UIModalTransitionStyleFlipHorizontal、UIModalTransitionStyleCrossDissolve、UIModalTransitionStylePartialCurl.具體每種style的表現形式參考Demo.

原地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章