UIViewController
有個屬性modalPresentationStyle
,它決定了當前控制器 present 出的下一控制器的展示方式。
官方文件對這些效果有比較詳細的介紹,這裡寫個 demo 幫助理解,demo 在模擬器上執行可能會有一點卡頓,真機沒有影響。
預備知識
presenting、presented viewController
presentingViewController
指的是 present 出當前控制器的控制器。
presentedViewController
指被當前控制器 present 出的控制器。
Size Class
對於各種常見情況的 Size Class 如下幾張圖片所示:



UIModalPresentationStyle
enum UIModalPresentationStyle : Int {
case fullScreen
case pageSheet
case formSheet
case currentContext
case custom
case overFullScreen
case overCurrentContext
case popover
case none
}
複製程式碼
fullScreen
- 在各種 Size Class 情況下都是全屏展示
- 執行 present 操作的控制器的
view
和它的subViews
,在 present 完成後都會被從當前檢視層級移除

對於水平方向為 compact 的情況,不管用哪種 style 推出其他控制器,presentedViewController
都是以fullScreen
方式展示。所以剩下的所有型別,都只針對水平方向為 regular 論述。
pageSheet
- 被推出檢視部分的遮蓋下層檢視
- 其寬度總是為該裝置豎屏時候的寬度(不可變),高度則為當前裝置方向的螢幕高度(可變,其實還要去掉狀態列的高度)


formSheet
- 被推出檢視大小比螢幕的小,且總是居中顯示
- 在橫屏時,如果彈出了鍵盤,檢視位置會跟著上移
- 可以設定被推出檢視的
preferredContentSize
來設定它的大小


這裡設定了preferredContentSize = CGSize(width: 200, height: 200)
。
currentContext
- 可以用在 iPad
UISplitViewController
中,指定單獨覆蓋螢幕單側的控制器;popover
方式展示的控制器,再用該方式 present 出下一檢視 - 在執行 present 操作的控制器的控制器層級中往上查詢,如果某個控制器的
definesPresentationContext == true
則它來 present,假如沒有一個為true
,那麼則由window.rootController
來 present - 執行 present 操作的控制器的
view
和它的subViews
,在 present 完成後都會被從當前檢視層級移除
definesPresentationContext
預設為false
,系統提供的一些像UINavigationController
的控制器,其預設值為true
。它的定義為:
A Boolean value that indicates whether this view controller's view is covered when the view controller or one of its descendants presents a view controller.
對於以currentContext
方式推出的檢視,如果它的presentedViewController
是一個popover
,那麼推出該檢視的modalTransitionStyle
不能是partialCurl
,否則會引起崩潰。



custom
A custom view presentation style that is managed by a custom presentation controller and one or more custom animator objects.
詳細介紹在下篇文章中進行。
overFullScreen
基本和fullScreen
一致。只是 present 完成後,不會移除執行 present 操作的控制器的view
和它的subViews
。如果presentedViewController.view
是有透明度的,底層檢視就可以得以顯示。

overCurrentContext
基本和currentContext
一致。只是 present 完成後,不會移除執行 present 操作的控制器的view
和它的subViews
。如果presentedViewController.view
是有透明度的,底層檢視就可以得以顯示。

popover
- 在 iPad 上用
popover
的方式顯示;在 iPhone 上預設用fullScreen
方式顯示,但是在 iOS8 後可以設定成popover
的方式,在none
中會進行解釋 - 預設情況下,點選灰色的背景
popover
會直接消失,通過presentedViewController.popoverPresentationController?.passthroughViews
可以配置灰色背景的哪些檢視區域可以點選
UIPopoverPresentationController
的定義:
An object that manages the display of content in a popover.
當檢視被用popover
方式 present 的時候,總有一個popoverPresentationController
的例項來管理呈現的行為。

none
- 該列舉值不可以直接賦值給
modalPresentationStyle
popoverPresentationController
會呼叫它delegate
的方法來配置popover
的檢視,none
只能用在adaptivePresentationStyle(for:)
代理方法中返回,告訴popoverPresentationController
不要適配presentedViewController
,這樣在 iPhone 中也可以用popover
的樣式展示了
