在屏幕上顯示視圖控制器有兩種方法:嵌入到容器視圖控制器中或者present這個視圖控制器。容器視圖控制器提供應用的主要導航,但present視圖控制器同樣也是一個重要的導航工具??梢栽诋斍暗囊晥D控制器上直接present一個新的視圖控制器。通常,當你希望實現modal界面時,可以present視圖控制器,但你也可以使用它們用于其他用途。
UIViewController 類支持present視圖控制器,可用于所有的視圖控制器對象。你可以在任何其他視圖控制器上present任何一個視圖控制器,雖然UIKit可能重新路由該請求到不同的視圖控制器上。present視圖控制器會在原始視圖控制器之間創建關系,原始視圖控制器稱為 presenting view controller,顯示的新視圖控制器稱為presented view controller。這個關系是視圖控制器層級結構的一部分,直到presented視圖控制器被dismiss。
展示和過渡的過程
present一個視圖控制器是一種快速而簡單的方法在屏幕上推出新內容。UIKit內置present機制,允許使用內置或自定義動畫來顯示一個新的視圖控制器。內置present和動畫需要很少的代碼因為UIKit處理了所有的工作。你也可以很容易的在任何視圖控制器創建自定義present和動畫。
你可以以編程方式或使用segue來發起視圖控制器的present。如果在設計時你知道應用的導航,segue是發起present最簡單的方式。更多動態界面,或者沒有專門的控件發起segue的情況下,使用 UIViewController方法來present視圖控制器。
Presentation Styles
presentation style 是一個視圖控制器管理其屏幕上的外觀。UIKit定義了許多標準的present風格,每個都有特定的外觀和意圖。你也可以定義自定義present風格。當設計你的應用時,為你的應用選擇合適的present風格,并為要present的視圖控制器的 modalPresentationStyle屬性分配適合的常數。
Full-Screen Presentation Styles
Full screen presentation styles覆蓋全部屏幕,防止與底層內容互動。在水平常規環境中,只有full-screen styles完全覆蓋了底層內容。其余變暗或有透明度的視圖允許部分底層視圖控制器顯示。在水平緊湊環境中,full-screen present方式自動采用UIModalPresentationFullScreen
風格并覆蓋所有底層內容。
圖8-1 說明在水平常規環境使用UIModalPresentationFullScreen,UIModalPresentationPageSheet和UIModalPresentationFormSheet風格present方式的外觀。在圖中,在左上角的綠色視圖控制器present在右上角的藍色視圖控制器,各種present風格如下。對于一些present風格,UIKit在兩個視圖控制器內容之間插入一個半透明視圖。
注意
當使用
UIModalPresentationFullScreen
風格present一個視圖控制器時,UIKit通常在完成過渡動畫后刪除底層視圖控制器的視圖。你可以通過指定UIModalPresentationOverFullScreen風格防止刪除這些視圖。當present的視圖控制器有透明區域讓底層內容顯示時可以采用這種風格。
當使用一種present 風格時,視圖控制器啟動的present必須覆蓋整個屏幕。如果將要present的視圖控制器不能覆蓋整個屏幕,UIKit遍歷視圖控制器層級直到找到一個覆蓋整個屏幕的視圖控制器。如果不能找到一個中間視圖控制器充滿屏幕,UIKit使用窗口的根視圖控制器。
The Popover Style
UIModalPresentationPopover風格以彈出窗口的方式顯示在視圖控制器上。popover用于顯示額外信息或項目列表中選中的對象。在橫向常規環境中,popover視圖僅覆蓋屏幕的一部分,如圖8-2所示。在橫向緊湊環境中,popover默認采用UIModalPresentationOverFullScreen present方式。在popover視圖外點擊, popover視圖將自動dismiss。
因為在水平緊湊環境中,popover采用full-screen 的present方式,通常需要修改popover代碼處理適配。在full-screen模式,需要一種方法dismiss掉present的popover。你可以通過添加一個按鈕,將popover嵌入到將要dismiss的容器視圖控制器,或者改變自適應行為本身。
如何配置彈窗,參見在視圖控制器上present彈窗( Presenting a View Controller in a Popover)。
The Current Context Styles
UIModalPresentationCurrentContext 風格在界面覆蓋了一個特殊的視圖控制器。當使用contextual風格,通過設置 definesPresentationContext屬性為YES,指定要覆蓋的視圖控制器。圖8-3說明了current context 只覆蓋分屏視圖控制器的一個子視圖控制器。
注意
當使用
UIModalPresentationFullScreen
風格present一個視圖控制器,UIKit通常在過渡動畫完成后刪除底層視圖控制器的視圖??梢栽O置UIModalPresentationOverCurrentContext風格,防止刪除那些視圖。當present的視圖控制器有透明區域讓底層內容顯示時,可以使用該風格。
定義視圖控制器還可以在present過程中定義過渡動畫。通常,當使用present視圖控制器的 modalTransitionStyle屬性,UIKit渲染視圖控制器到屏幕。如果present context視圖控制器的 providesPresentationContextTransitionStyle值設為YES,UIKit使用視圖控制器的modalTransitionStyle
屬性代替。
當過渡到水平緊湊的環境,current context風格采用 UIModalPresentationFullScreen 風格。為了改變該行為,使用自適應present委托指定不同的present風格或視圖控制器。
Custom Presentation Styles
UIModalPresentationCustom風格使用自定義的風格present視圖控制器。創建一個自定義風格包括子類化UIPresentationController ,使用其方法來渲染任何自定義視圖到屏幕上并設置present視圖控制器的大小和位置。present控制器還處理由于視圖控制器的trait變化引起的適配。
如何定義自定義present視圖控制器的信息,參見創建自定義present( Creating Custom Presentations)。
Transition Styles
Transition風格決定用于顯示present視圖控制器的動畫類型。對于內置transition風格,你可以為present視圖控制器的 modalTransitionStyle屬性指定一種標準transition風格。當present視圖控制器,UIKit創建相應的動畫風格。例如,圖8-4說明了標準slide-up過渡(UIModalTransitionStyleCoverVertical)如何視圖控制器渲染到屏幕上。視圖控制器B開始在屏幕外,并覆蓋到視圖控制器A上。當dismiss視圖控制器B,動畫逆轉,B下滑露出A。
可以使用動畫對象和過渡代理來創建自定義過渡。動畫對象為屏幕上放置的視圖控制器創建過渡動畫。過渡代理在合適的時間為UIKit提供動畫對象。更多關于如何實現自定義過渡的信息,參見自定義過渡動畫(Customizing the Transition Animations)。
present和顯示一個視圖控制器
UIViewController類提供兩種方法來顯示一個視圖控制器:
- showViewController:sender:和 showDetailViewController:sender:方法為顯示視圖控制器提供最大限度的適應性和靈活性。這些方法讓present視圖控制器決定如何最好的處理present。例如,容器視圖控制器可能合并視圖控制器作為子視圖控制器而不是以模態的方式present。默認以模態的方式present視圖控制器。
- presentViewController:animated:completion: 方法總是以模態的方式顯示視圖控制器。視圖控制器調用這個方法可能不會最終處理present但總是以模態的方式present。在水平緊湊環境中,該方法采用該present風格。
showViewController:sender:
和showDetailViewController:sender:
方法是啟動present的首選方法。視圖控制器可以調用它們,而不用知道任何關于視圖控制器層級結構或當前視圖控制器在層級結構的位置。這些方法使重用視圖控制器更加容易,而無需編寫條件代碼路徑。
present視圖控制器
有幾種方法可以present視圖控制器:
- 使用segue自動present視圖控制器。使用界面構建器指定的信息,segue實例化并present視圖控制器。關于如何配置segue的更多信息,參見使用segue( Using Segues)。
- 使用 showViewController:sender: 和 showDetailViewController:sender:方法顯示視圖控制器。在自定義視圖控制器中,可以改變這些方法的行為使之更加適合你的視圖控制器。
- 調用presentViewController:animated:completion:方法以模態的方式present視圖控制器。
關于如何dismiss使用這些技術present的視圖控制的更多信息,參見dismiss一個presented的視圖控制器( Dismissing a Presented View Controller)。
顯示視圖控制器
當使用和方法,得到屏幕上一個新的視圖控制器的過程很簡單:
- 創建你希望present的視圖控制器對象。當創建視圖控制器時,你負責初始化它執行任何所需的任何數據。
- 設置新視圖控制器的 modalPresentationStyle屬性是首選present風格。該風格可能不用于最終的present。
- 設置視圖控制器的modalTransitionStyle屬性設置所需的過渡動畫風格。該風格可能不用于最終的present。
- 調用當前視圖控制器的 showViewController:sender:和showDetailViewController:sender:方法。
UIKit轉發showViewController:sender:
和showDetailViewController:sender:
方法的調用給present視圖控制器。視圖控制器可以決定如何最好的執行present,并且可以根據需呀改變present和過渡風格。例如,導航控制器可能push該視圖控制器到導航堆棧。
關于顯示視圖控制器和以模態的方式present視圖控制器的差異信息,參見present和顯示視圖控制器( Presenting Versus Showing a View Controller)。
以模態的方式present視圖控制器
當直接present視圖控制器,你需要告訴UIKit你希望視圖控制器如何顯示以及如何渲染到屏幕上。
創建你希望present的視圖控制器對象。當創建視圖控制器時,你負責初始化它執行任何所需的任何數據。
- 設置新視圖控制器的 modalPresentationStyle 屬性為所需的present風格。
- 設置視圖控制器的 modalTransitionStyle屬性為所需的動畫風格。
- 調用當前視圖控制器的 presentViewController:animated:completion:方法。
調用presentViewController:animated:completion:
方法的視圖控制器可能不是最終執行模態present的視圖控制器。present風格決定了視圖控制器如何被present,包括present視圖控制器所需的特征。例如,一個全屏present必須由一個全屏視圖控制器啟動。如果當前present視圖控制器不合適,UIKit遍歷視圖控制器層級直到找到合適的。完成模態present后,UIKit更新受影響的視圖控制器的presentingViewController和 presentedViewController屬性。
列表8-1 演示了如何以編程的方式present一個視圖控制器。當用戶添加一個新視圖控制器,應用提示用戶輸入present導航視圖控制器的基本信息。被選中的導航控制器會在標準的地方放置一個取消和完成按鈕。使用導航控制器使擴展新界面更加容易。你所需要做的是push新視圖控制器到導航堆棧。
列表8-1 以編程的方式present一個視圖控制器
<pre><code>
- (void)add:(id)sender {
- // Create the root view controller for the navigation controller
- // The new view controller configures a Cancel and Done button for the
- // navigation bar.
- RecipeAddViewController *addController = [[RecipeAddViewController alloc] init];
- addController.modalPresentationStyle = UIModalPresentationFullScreen;
- addController.transitionStyle = UIModalTransitionStyleCoverVertical;
- [self presentViewController:addController animated:YES completion: nil];
- }
</pre></code>
以彈窗形式present視圖控制器
在present視圖控制器之前,popover需要額外的配置。在設置模態present風格為 UIModalPresentationPopover后,配置一下popover相關屬性:
- 設置視圖控制器的 preferredContentSize屬性為所需的大小。
- 使用相關UIPopoverPresentationController對象設置popover錨點,該對象可用于視圖控制器的 popoverPresentationController屬性。設置一下其中一種:
- -設置屬性為bar button。
- -設置 sourceView 和 sourceRect屬性指定特定視圖區域。
可以使用 UIPopoverPresentationController對象在需要時調整彈窗的外觀。彈窗present控制器還支持代理對象,可以使用它來響應在present過程中的變化。例如,你可以使用代理來響應彈窗在屏幕上出現、消失或重新定位。關于該對象的更多信息,參見UIPopoverPresentationController類引用(UIPopoverPresentationController Class Reference)。
dismiss一個presented的視圖控制器
調用presenting視圖控制器的dismissViewControllerAnimated:completion:方法來dismiss一個presented的視圖控制器。你可以在presented視圖控制器本身的方法。當presented視圖控制器調用該方法,UIKit自動轉發請求到presenting視圖控制器。
在dismiss視圖控制器前保存任何重要信息。dismiss視圖控制器會將其從視圖控制器層級結構刪除并從屏幕上刪除視圖。如果在其他地方存儲的視圖控制器沒有強引用,dismiss該視圖控制器會釋放與之關聯的內存。
如果presented視圖控制器必須返回數據到presenting視圖控制器,使用 delegation 設計模式來完成傳遞。代理使應用視圖控制器的重用更容易。使用代理,presented視圖控制器存儲代理對象的引用,實現正式protocol的方法。Presented視圖控制器在代理調用這些方法用于收集結果。在典型的實現中,presenting視圖控制器作為presented視圖控制器的代理。
present在不同storyboard種定義的視圖控制器
雖然在同一storyboard中的兩個視圖控制器之間可以創建segue,但在不同storyboard中不能創建segue。當你希望顯示存儲在另一個storyboard中的視圖控制器時,你必須在present之前顯式的實例化該視圖控制器,如列表8-2所示。例子以模態的方式present視圖控制器,但你可以push它到導航控制器或以其他方式顯示。
列表8-2 加載storyboard中的視圖控制器
<pre><code>
- UIStoryboard* sb = [UIStoryboard storyboardWithName:@"SecondStoryboard" bundle:nil];
- MyViewController* myVC = [sb instantiateViewControllerWithIdentifier:@"MyViewController"];
- // Configure the view controller.
- // Display the view controller
- [self presentViewController:myVC animated:YES completion:nil];
</pre></code>
沒有要求你必須在應用中創建多個storyboard。不過,在這里有一些情況下多個storyboard可能有用:
- 你有一個大的編程團隊,不同的用戶界面分配給團隊的不同部分。每個團隊擁有不同的storyboard文件以減少沖突。
- 你購買或創建一個庫預定義了視圖控制器類型集合;這些視圖控制器的內容定義在庫中的storyboard中。
- 你有需要在屏幕外顯示的內容。在這種情況下,你可能保持所有視圖控制器與單獨storyboard的視圖控制器相關。相同場景的另一種模式是編寫一個自定義segue。