iOS review系列之使用Segues
iOS review系列之自定義轉場動畫
iOS review系列之Presenting a View Controller
iOS review系列之UIViewController
UIKit將視圖控制器的內容與內容在屏幕上顯示的方式分開。Presented視圖控制器由底層的presentation控制器對象管理,該對象管理用于顯示視圖控制器視圖的視覺樣式。presentation控制器可以執行以下操作:
- 設置 presented控制器的大小。
- 添加自定義視圖來更改presented內容的視覺外觀。
- 為它的任何自定義視圖提供轉場動畫。
- 當app的環境發生變化時,調整presentation的視覺外觀。
UIKit為標準presentation樣式提供了presentation控制器。當你將視圖控制器的presentation樣式設置為UIModalPresentationCustom
并提供一個適當的轉場代理時,UIKit會使用你的自定義presentation控制器。
自定義presentation過程
當你present一個視圖控制器,它的presentation風格是UIModalPresentationCustom
, UIKit尋找一個自定義的presentation控制器來管理presentation過程。隨著presentation的進展,UIKit調用presentation控制器的方法,讓它有機會設置任何自定義視圖并使它們動起來。
presentation控制器與任何animator對象一起工作來實現整個轉場。animator對象將視圖控制器的內容動畫到屏幕上,而presentation controller處理所有其他事情。通常,您的presentation控制器會使它自己的視圖具有動畫效果,但是您也可以重寫presentation控制器的presentedView
方法,并讓animator對象使所有或部分視圖具有動畫效果。
在一次presentation中,UIKit:
調用
presentationControllerForPresentedViewController:presentingViewController:sourceViewController:
的轉場方法來檢索您的自定義presentation控制器詢問Animator和交互式Animator對象的轉場代理(如果有的話)
調用presentation controller的
presentationTransitionWillBegin
方法,此方法的實現應該將任何自定義視圖添加到視圖層次結構中,并為這些視圖配置動畫。-
從presentation控制器獲取
presentedView
此方法返回的視圖由animator對象動畫到指定位置。通常,這個方法返回被呈現的presented視圖控制器的根視圖。您的presentation控制器可以根據需要用自定義背景視圖替換該視圖。如果你指定了一個不同的視圖,你必須將當前視圖控制器的根視圖嵌入到你的視圖層次結構中。
-
執行轉場動畫
轉場動畫包括animator對象創建的主動畫和配置為與主動畫一起運行的任何動畫。有關轉場動畫的信息,請參閱轉場動畫序列。
在動畫過程中,UIKit調用你的presentation控制器的
containerViewWillLayoutSubviews
和containerViewDidLayoutSubviews
方法,這樣你可以根據需要調整你自定義視圖的布局。 在轉場動畫完成時調用
presentationTransitionDidEnd:
方法
在dismissal期間,UIKit:
從當前可見的視圖控制器獲取自定義presentation控制器
詢問Animator和交互式Animator對象的轉場代理(如果有的話)
-
調用presentation controller的
dismissalTransitionWillBegin
方法此方法的實現應該將任何自定義視圖添加到視圖層次結構中,并為這些視圖配置動畫。
從presentation控制器獲取
presentedView
-
執行轉場動畫
轉場動畫包括Animator對象創建的主動畫和配置為與主動畫一起運行的任何動畫。有關轉場動畫的信息,請參閱轉場動畫序列。
在動畫過程中,UIKit調用你的presentation控制器的
containerViewWillLayoutSubviews
和containerViewDidLayoutSubviews
方法,這樣你可以根據需要調整你自定義視圖的布局 在轉場動畫完成時調用
dismissalTransitionDidEnd:
方法
在presentation過程中,您的presentation控制器的frameOfPresentedViewInContainerView
和presentedView
方法可能會被調用多次,因此您的實現應該快速返回。另外,presentedView
方法的實現不應該嘗試設置視圖層次結構。在調用方法時,視圖層次結構應該已經配置好了。
Creating a Custom Presentation Controller
要實現自定義presentation樣式,可以子類化UIPresentationController并添加代碼來創建演示的視圖和動畫。在創建自定義presentation控制器時,請考慮以下問題:
您想添加什么視圖?
如何在屏幕上設置其他視圖的動畫?
presented視圖控制器應該是多大?
presentation如何在水平規則類和水平緊湊類屏幕之間進行調整?
是否應該在presentation結束時移除呈現視圖控制器的視圖?
所有這些決策都需要重寫UIPresentationController
類的不同方法。
設置Presented視圖控制器的Frame
您可以修改Presented視圖控制器的 frame rectangle,使其只填充部分可用空間。默認情況下,Presented視圖控制器的大小完全填充容器視圖的Frame。要更改 frame rectangle,請重寫Presented控制器的frameOfPresentedViewInContainerView
方法。清單11-1顯示了一個示例,其中frame被更改為只覆蓋容器視圖的右半部分。在本例中,Presented控制器使用background dimming view來重寫容器的另一半。
- (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;
}
Managing and Animating Custom Views
自定義presentation通常涉及到向presented內容中添加自定義視圖。使用自定義視圖實現純粹的視覺裝飾,或使用它們向presentation添加實際行為。例如,背景視圖可以合并手勢識別器來跟蹤presented內容范圍之外的特定操作。
presentation控制器負責創建和管理與其表示相關聯的所有自定義視圖。通常,在presentation控制器初始化期間創建自定義視圖。清單11-2顯示了自定義視圖控制器的初始化方法,它創建了自己的 dimming view。此方法創建視圖并執行一些最小配置。
- (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
方法將自定義視圖動畫到屏幕上。在此方法中,配置自定義視圖并將其添加到容器視圖,如下代碼所示。使用presented視圖控制器或presenting視圖控制器的轉場協調器來創建任何動畫。不要在這個方法中修改當前視圖控制器的視圖。animator對象負責將presented視圖控制器動畫到從frameOfPresentedViewInContainerView
方法返回的frame rectangle中。
- (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];
}
}
在presentation結束時,使用presentationTransitionDidEnd:
方法來處理由于presentation取消而引起的任何清理。如果不滿足其閾值條件,交互式animator對象可能會取消轉場。當這種情況發生時,UIKit調用presentationTransitionDidEnd:
方法,它的返回值是NO
。當取消發生時,刪除您在presentation開始時添加的任何自定義視圖,并將任何其他視圖返回到它們以前的配置,如下代碼所示。
- (void)presentationTransitionDidEnd:(BOOL)completed {
// If the presentation was canceled, remove the dimming view.
if (!completed)
[self.dimmingView removeFromSuperview];
}
當視圖控制器被dismissed時,使用dismissalTransitionDidEnd:
方法從視圖層次結構中移除你的自定義視圖。如果你想讓你的視圖消失動畫化,在dismissalTransitionDidEnd:
方法中設置那些動畫。下面代碼展示了在前面的示例中移除dimming view的兩種方法的實現。始終檢查dismissalTransitionDidEnd:
方法的參數,以查看dismissal是否成功或被取消。
- (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];
}
Vending Your Presentation Controller to UIKit
當呈現一個視圖控制器時,執行以下操作來使用您的自定義presentation控制器顯示它:
- 將當前視圖控制器的
modalPresentationStyle
屬性設置為UIModalPresentationCustom
。 - 將一個轉場代理分配給被presented視圖控制器的
transitioningDelegate
屬性 - 實現
presentationControllerForPresentedViewController:presentingViewController:sourceViewController:
轉場代理的方法。
在需要你的presentation控制器,UIKit調用轉場代理的presentationControllerForPresentedViewController:presentingViewController:sourceViewController:
方法。這個方法的實現應該與下面代碼中的方法一樣簡單。只需創建presentation控制器,配置它并返回它。如果你從這個方法返回nil, UIKit會用全屏顯示風格來顯示視圖控制器。
- (UIPresentationController *)presentationControllerForPresentedViewController:
(UIViewController *)presented
presentingViewController:(UIViewController *)presenting
sourceViewController:(UIViewController *)source {
MyPresentationController* myPresentation = [[MyPresentationController]
initWithPresentedViewController:presented presentingViewController:presenting];
return myPresentation;
}