UIKit將視圖控制器的內(nèi)容與內(nèi)容在屏幕上顯示和呈現(xiàn)的方式分離。 呈現(xiàn)的視圖控制器由底層呈現(xiàn)控制器對(duì)象管理,其管理用于呈現(xiàn)視圖控制器的視圖的視覺(jué)樣式。 呈現(xiàn)控制器可以執(zhí)行以下操作:
- 設(shè)置提供的視圖控制器的大小。
- 添加自定義視圖以更改所顯示內(nèi)容的視覺(jué)外觀。
- 為任何它的自定義視圖提供過(guò)渡動(dòng)畫。
- 在應(yīng)用程序環(huán)境中發(fā)生更改時(shí)調(diào)整呈現(xiàn)視圖的視覺(jué)外觀。
UIKit提供了標(biāo)準(zhǔn)呈現(xiàn)方式的呈現(xiàn)控制器。 當(dāng)您將視圖控制器的呈現(xiàn)樣式設(shè)置為UIModalPresentationCustom并提供適當(dāng)?shù)霓D(zhuǎn)換委托時(shí),UIKit將使用您的自定義呈現(xiàn)控制器。
自定義呈現(xiàn)過(guò)程
當(dāng)您呈現(xiàn)其呈現(xiàn)樣式為UIModalPresentationCustom的視圖控制器時(shí),UIKit會(huì)查找自定義的顯示控制器來(lái)管理呈現(xiàn)過(guò)程。 隨著呈現(xiàn)的進(jìn)行,UIKit調(diào)用呈現(xiàn)控制器的方法,讓它有機(jī)會(huì)設(shè)置任何自定義視圖并將它們動(dòng)畫化到位置。
呈現(xiàn)控制器與任何動(dòng)畫對(duì)象一起工作,以實(shí)現(xiàn)整體轉(zhuǎn)換。 該動(dòng)畫對(duì)象將視圖控制器的內(nèi)容動(dòng)畫化到屏幕上,并且呈現(xiàn)控制器處理一切。 通常,你的呈現(xiàn)控制器會(huì)自動(dòng)生成自己的視圖,但您也可以覆蓋呈現(xiàn)控制器的presentView方法,該動(dòng)畫對(duì)象對(duì)所有或部分視圖進(jìn)行動(dòng)畫處理。
在呈現(xiàn)期間,UIKit:
調(diào)用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:轉(zhuǎn)換委托的方法來(lái)檢索您的自定義呈現(xiàn)控制器
詢問(wèn)動(dòng)畫和交互式動(dòng)畫對(duì)象的轉(zhuǎn)換委托(如果有的話)
調(diào)用呈現(xiàn)控制器的presentationTransitionWillBegin方法您的此方法的實(shí)現(xiàn)應(yīng)將任何自定義視圖添加到視圖層次結(jié)構(gòu)并配置這些視圖的動(dòng)畫。
從呈現(xiàn)控制器獲取presentView此方法返回的視圖由動(dòng)畫對(duì)象動(dòng)畫定位。 通常,此方法返回所呈現(xiàn)的視圖控制器的根視圖。 你的呈現(xiàn)控制器可以根據(jù)需要使用自定義背景視圖替換該視圖。 如果你指定了其他視圖,則必須將提供的視圖控制器的根視圖嵌入到視圖層次結(jié)構(gòu)中。
執(zhí)行轉(zhuǎn)換動(dòng)畫
過(guò)渡動(dòng)畫包括由動(dòng)畫師對(duì)象創(chuàng)建的主要?jiǎng)赢嫞约澳闩渲脼榕c主要?jiǎng)赢嫴⑿羞\(yùn)行的任何動(dòng)畫。 在動(dòng)畫過(guò)程中,UIKit調(diào)用演示控制器的containerViewWillLayoutSubviews和containerViewDidLayoutSubviews方法,以便您可以根據(jù)需要調(diào)整自定義視圖的布局。轉(zhuǎn)換動(dòng)畫完成時(shí)調(diào)用presentationTransitionDidEnd:方法
在關(guān)閉期間,UIKit:
- 從當(dāng)前可見(jiàn)的視圖控制器獲取您的自定義呈現(xiàn)控制器
- 詢問(wèn)動(dòng)畫和交互式動(dòng)畫對(duì)象的轉(zhuǎn)換委托(如果有的話)
- 調(diào)用呈現(xiàn)控制器的dismissalTransitionWillBegin方法
你的方法的實(shí)現(xiàn)應(yīng)將任何自定義視圖添加到視圖層次結(jié)構(gòu)并配置這些視圖的動(dòng)畫。 - 從呈現(xiàn)控制器獲取已經(jīng)呈現(xiàn)的視圖
- 執(zhí)行轉(zhuǎn)換動(dòng)畫
過(guò)渡動(dòng)畫包括由動(dòng)畫師對(duì)象創(chuàng)建的主要?jiǎng)赢嫞约澳闩渲脼榕c主要?jiǎng)赢嫴⑿羞\(yùn)行的任何動(dòng)畫。 在動(dòng)畫過(guò)程中,UIKit調(diào)用呈現(xiàn)控制器的containerViewWillLayoutSubviews和containerViewDidLayoutSubviews方法,以便您可以刪除任何自定義約束。 - 轉(zhuǎn)換動(dòng)畫完成時(shí)調(diào)用dismissalTransitionDidEnd:方法
在呈現(xiàn)過(guò)程中,你的呈現(xiàn)控制器的frameOfPresentedViewInContainerView和presentedView方法可能會(huì)被調(diào)用多次,因此您的實(shí)現(xiàn)應(yīng)該很快返回。 此外,您的presentView方法的實(shí)現(xiàn)不應(yīng)該嘗試設(shè)置視圖層次結(jié)構(gòu)。 視圖層次結(jié)構(gòu)應(yīng)該在調(diào)用方法時(shí)進(jìn)行配置。
創(chuàng)建自定義呈現(xiàn)控制器
要實(shí)現(xiàn)自定義呈現(xiàn)風(fēng)格,請(qǐng)將UIPresentationController子類化并添加代碼以創(chuàng)建呈現(xiàn)控制器的視圖和動(dòng)畫。 創(chuàng)建自定義呈現(xiàn)控制器時(shí),請(qǐng)考慮以下問(wèn)題:
- 你要添加哪些視圖?
- 如何在屏幕上為任何其他視圖設(shè)置動(dòng)畫?
- 應(yīng)該是什么大小的呈現(xiàn)視圖控制器?
- 應(yīng)該如何在水平規(guī)則和水平緊湊的尺寸類之間進(jìn)行調(diào)整?
- 呈現(xiàn)完成后,應(yīng)該刪除呈現(xiàn)視圖控制器的視圖嗎?
所有這些決定都需要覆蓋UIPresentationController類的不同方法。
設(shè)置呈現(xiàn)的視圖控制器的Frame
你可以修改呈現(xiàn)的視圖控制器的框架矩形,以便它只填充部分可用空間。 默認(rèn)情況下,呈現(xiàn)的視圖控制器的大小設(shè)置為完全填充容器視圖的框架。 要更改框架矩形,重寫呈現(xiàn)控制器的frameOfPresentedViewInContainerView方法。 代碼清單11-1顯示了一個(gè)示例,其中框架更改為僅覆蓋容器視圖的右半部分。 在這種情況下,呈現(xiàn)控制器使用背景調(diào)暗視圖來(lái)覆蓋容器的另一半。
代碼清單11-1更改所呈現(xiàn)視圖控制器的frame
- (CGRect)frameOfPresentedViewInContainerView {
CGRect presentedViewFrame = CGRectZero;
CGRect containerBounds = [[self containerView] bounds];
presentedViewFrame.size = CGSizeMake(floorf(containerBounds.size.width / 2.0),
containerBounds.size.height);
presentedViewFrame.origin.x = containerBounds.size.width -
presentedViewFrame.size.width;
return presentedViewFrame;
}
管理和動(dòng)畫自定義視圖
自定義呈現(xiàn)通常涉及向所呈現(xiàn)的內(nèi)容添加自定義視圖。 使用自定義視圖來(lái)實(shí)現(xiàn)純視覺(jué)裝飾,或使用它們向呈現(xiàn)控制器添加實(shí)用行為。 例如,背景視圖可以包括姿勢(shì)識(shí)別器以跟蹤所呈現(xiàn)內(nèi)容的界限之外的特定動(dòng)作。
呈現(xiàn)控制器負(fù)責(zé)創(chuàng)建和管理與其呈現(xiàn)相關(guān)聯(lián)的所有自定義視圖。 通常,您在呈現(xiàn)控制器的初始化期間創(chuàng)建自定義視圖。 代碼清單11-2顯示了創(chuàng)建自己的調(diào)光視圖的自定義視圖控制器的初始化方法。 此方法創(chuàng)建視圖并執(zhí)行一些最小配置。
代碼清單11-2初始化表示控制器
- (instancetype)initWithPresentedViewController:(UIViewController *)presentedViewController
presentingViewController:(UIViewController *)presentingViewController {
self = [super initWithPresentedViewController:presentedViewController
presentingViewController:presentingViewController];
if(self) {
// Create the dimming view and set its initial appearance.
self.dimmingView = [[UIView alloc] init];
[self.dimmingView setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.4]];
[self.dimmingView setAlpha:0.0];
}
return self;
}
您使用presentationTransitionWillBegin方法在屏幕上動(dòng)畫自定義視圖。 在此方法中,配置自定義視圖,并將它們添加到容器視圖中,如代碼清單11-3所示。 使用呈現(xiàn)或呈現(xiàn)視圖控制器的轉(zhuǎn)換協(xié)調(diào)器來(lái)創(chuàng)建任何動(dòng)畫。 在此方法中不要修改呈現(xiàn)的視圖控制器的視圖。 animator對(duì)象負(fù)責(zé)將呈現(xiàn)的視圖控制器動(dòng)畫化到從frameOfPresentedViewInContainerView方法返回的框架矩形中。
代碼清單11-3將調(diào)光視圖動(dòng)畫化到屏幕上
- (void)presentationTransitionWillBegin {
// Get critical information about the presentation.
UIView* containerView = [self containerView];
UIViewController* presentedViewController = [self presentedViewController];
// Set the dimming view to the size of the container's
// bounds, and make it transparent initially.
[[self dimmingView] setFrame:[containerView bounds]];
[[self dimmingView] setAlpha:0.0];
// Insert the dimming view below everything else.
[containerView insertSubview:[self dimmingView] atIndex:0];
// Set up the animations for fading in the dimming view.
if([presentedViewController transitionCoordinator]) {
[[presentedViewController transitionCoordinator]
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>
context) {
// Fade in the dimming view.
[[self dimmingView] setAlpha:1.0];
} completion:nil];
}
else {
[[self dimmingView] setAlpha:1.0];
}
}
在呈現(xiàn)控制器結(jié)束時(shí),使用presentationTransitionDidEnd:方法處理由呈現(xiàn)控制器取消引起的任何清除操作。 如果不滿足條件,交互式動(dòng)畫對(duì)象可能會(huì)取消轉(zhuǎn)換。 當(dāng)這種情況發(fā)生時(shí),UIKit調(diào)用presentationTransitionDidEnd:方法,值為NO。 取消操作時(shí),刪除在演示開(kāi)始時(shí)添加的任何自定義視圖,并將任何其他視圖返回到之前的配置,如代碼清單11-4所示。
- (void)presentationTransitionDidEnd:(BOOL)completed {
// If the presentation was canceled, remove the dimming view.
if (!completed)
[self.dimmingView removeFromSuperview];
}
當(dāng)視圖控制器被關(guān)閉時(shí),使用dismissalTransitionDidEnd:方法從視圖層次結(jié)構(gòu)中刪除自定義視圖。 如果你想動(dòng)畫你的視圖的消失,在dismissalTransitionDidEnd:方法中設(shè)置這些動(dòng)畫。 代碼清單11-5顯示了用于刪除前面示例中的調(diào)光視圖的兩種方法的實(shí)現(xiàn)。 始終檢查dismissalTransitionDidEnd:方法的參數(shù),以查看解除是成功還是已取消。
代碼清單11-5取消呈現(xiàn)控制器的視圖
- (void)dismissalTransitionWillBegin {
// Fade the dimming view back out.
if([[self presentedViewController] transitionCoordinator]) {
[[[self presentedViewController] transitionCoordinator]
animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>
context) {
[[self dimmingView] setAlpha:0.0];
} completion:nil];
}
else {
[[self dimmingView] setAlpha:0.0];
}
}
- (void)dismissalTransitionDidEnd:(BOOL)completed {
// If the dismissal was successful, remove the dimming view.
if (completed)
[self.dimmingView removeFromSuperview];
}
將您的呈現(xiàn)控制器控制權(quán)自動(dòng)給UIKit
呈現(xiàn)視圖控制器時(shí),請(qǐng)執(zhí)行以下操作,使用自定義演示控制器顯示它:
- 將提供的視圖控制器的modalPresentationStyle屬性設(shè)置為UIModalPresentationCustom。
- 將轉(zhuǎn)換委托分配給所呈現(xiàn)的視圖控制器的transitioningDelegate屬性。
- 實(shí)現(xiàn)presentationControllerForPresentedViewController:presentingViewController:sourceViewController:轉(zhuǎn)換委托的方法。
UIKit調(diào)用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:當(dāng)您需要呈現(xiàn)控制器時(shí),您的轉(zhuǎn)換委托的方法。 這個(gè)方法的實(shí)現(xiàn)應(yīng)該和代碼清單11-6中的一樣簡(jiǎn)單。 只需創(chuàng)建呈現(xiàn)控制器,配置它,并返回它。 如果從此方法返回nil,UIKit使用全屏呈現(xiàn)樣式呈現(xiàn)視圖控制器。
代碼清單11-6創(chuàng)建自定義呈現(xiàn)控制器
- (UIPresentationController *)presentationControllerForPresentedViewController:
(UIViewController *)presented
presentingViewController:(UIViewController *)presenting
sourceViewController:(UIViewController *)source {
MyPresentationController* myPresentation = [[MyPresentationController]
initWithPresentedViewController:presented presentingViewController:presenting];
return myPresentation;
}
適應(yīng)不同大小類
當(dāng)呈現(xiàn)在屏幕上時(shí),UIKit通知您的呈現(xiàn)控制器基礎(chǔ)特征或容器視圖的大小發(fā)生變化。 這種變化通常在設(shè)備旋轉(zhuǎn)期間發(fā)生,但可以在其他時(shí)間發(fā)生。 您可以使用特征和大小通知來(lái)調(diào)整呈現(xiàn)控制器的自定義視圖,并根據(jù)需要更新呈現(xiàn)控制器樣式。