ViewController編程指南展示和過(guò)渡-創(chuàng)建自定義呈現(xiàn)

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:

  1. 調(diào)用presentationControllerForPresentedViewController:presentingViewController:sourceViewController:轉(zhuǎn)換委托的方法來(lái)檢索您的自定義呈現(xiàn)控制器

  2. 詢問(wèn)動(dòng)畫和交互式動(dòng)畫對(duì)象的轉(zhuǎn)換委托(如果有的話)

  3. 調(diào)用呈現(xiàn)控制器的presentationTransitionWillBegin方法您的此方法的實(shí)現(xiàn)應(yīng)將任何自定義視圖添加到視圖層次結(jié)構(gòu)并配置這些視圖的動(dòng)畫。

  4. 從呈現(xiàn)控制器獲取presentView此方法返回的視圖由動(dòng)畫對(duì)象動(dòng)畫定位。 通常,此方法返回所呈現(xiàn)的視圖控制器的根視圖。 你的呈現(xiàn)控制器可以根據(jù)需要使用自定義背景視圖替換該視圖。 如果你指定了其他視圖,則必須將提供的視圖控制器的根視圖嵌入到視圖層次結(jié)構(gòu)中。

  5. 執(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)整自定義視圖的布局。

  6. 轉(zhuǎn)換動(dòng)畫完成時(shí)調(diào)用presentationTransitionDidEnd:方法

在關(guān)閉期間,UIKit:

  1. 從當(dāng)前可見(jiàn)的視圖控制器獲取您的自定義呈現(xiàn)控制器
  2. 詢問(wèn)動(dòng)畫和交互式動(dòng)畫對(duì)象的轉(zhuǎn)換委托(如果有的話)
  3. 調(diào)用呈現(xiàn)控制器的dismissalTransitionWillBegin方法
    你的方法的實(shí)現(xiàn)應(yīng)將任何自定義視圖添加到視圖層次結(jié)構(gòu)并配置這些視圖的動(dòng)畫。
  4. 從呈現(xiàn)控制器獲取已經(jīng)呈現(xiàn)的視圖
  5. 執(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方法,以便您可以刪除任何自定義約束。
  6. 轉(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)控制器樣式。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,786評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 176,986評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 63,204評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,964評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 55,354評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,554評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,106評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,918評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,093評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,342評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,755評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 36,009評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,839評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,107評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容