iOS review系列之Creating Custom Presentations

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:

  1. 調用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:的轉場方法來檢索您的自定義presentation控制器

  2. 詢問Animator和交互式Animator對象的轉場代理(如果有的話)

  3. 調用presentation controller的presentationTransitionWillBegin方法,此方法的實現應該將任何自定義視圖添加到視圖層次結構中,并為這些視圖配置動畫。

  4. 從presentation控制器獲取presentedView

    此方法返回的視圖由animator對象動畫到指定位置。通常,這個方法返回被呈現的presented視圖控制器的根視圖。您的presentation控制器可以根據需要用自定義背景視圖替換該視圖。如果你指定了一個不同的視圖,你必須將當前視圖控制器的根視圖嵌入到你的視圖層次結構中。

  5. 執行轉場動畫

    轉場動畫包括animator對象創建的主動畫和配置為與主動畫一起運行的任何動畫。有關轉場動畫的信息,請參閱轉場動畫序列。

    在動畫過程中,UIKit調用你的presentation控制器的containerViewWillLayoutSubviewscontainerViewDidLayoutSubviews方法,這樣你可以根據需要調整你自定義視圖的布局。

  6. 在轉場動畫完成時調用presentationTransitionDidEnd:方法

在dismissal期間,UIKit:

  1. 從當前可見的視圖控制器獲取自定義presentation控制器

  2. 詢問Animator和交互式Animator對象的轉場代理(如果有的話)

  3. 調用presentation controller的dismissalTransitionWillBegin方法

    此方法的實現應該將任何自定義視圖添加到視圖層次結構中,并為這些視圖配置動畫。

  4. 從presentation控制器獲取 presentedView

  5. 執行轉場動畫

    轉場動畫包括Animator對象創建的主動畫和配置為與主動畫一起運行的任何動畫。有關轉場動畫的信息,請參閱轉場動畫序列。

    在動畫過程中,UIKit調用你的presentation控制器的containerViewWillLayoutSubviewscontainerViewDidLayoutSubviews方法,這樣你可以根據需要調整你自定義視圖的布局

  6. 在轉場動畫完成時調用dismissalTransitionDidEnd:方法

在presentation過程中,您的presentation控制器的frameOfPresentedViewInContainerViewpresentedView方法可能會被調用多次,因此您的實現應該快速返回。另外,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控制器顯示它:

  1. 將當前視圖控制器的modalPresentationStyle屬性設置為UIModalPresentationCustom
  2. 將一個轉場代理分配給被presented視圖控制器的transitioningDelegate屬性
  3. 實現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;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容