這篇文章給大家分享的是有關(guān)iOS如何實(shí)現(xiàn)容器視圖控制器的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。
創(chuàng)新互聯(lián)是一家專業(yè)提供從江企業(yè)網(wǎng)站建設(shè),專注與成都做網(wǎng)站、網(wǎng)站制作、H5高端網(wǎng)站建設(shè)、小程序制作等業(yè)務(wù)。10年已為從江眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。
一直以來想寫一個(gè)抽屜效果,看了一些文章后發(fā)現(xiàn)并不是那么簡(jiǎn)單,網(wǎng)上的一些抽屜效果不是很嚴(yán)謹(jǐn)。看了下MMDrawerController的源碼,等于定制了一個(gè)Container View Controller。(類似于系統(tǒng)的UINavigationController以及UITabbarController);
比如下面幾個(gè)方法就是MMDrawerController實(shí)現(xiàn)的:
下面的描述是官方文檔幫助理解什么是容器控制器,文檔中以UINavigationController和UISplitViewController舉例。
容器視圖控制器是將來自多個(gè)視圖控制器的內(nèi)容合并到單個(gè)用戶界面中的一種方法。容器視圖控制器通常用于促進(jìn)導(dǎo)航,并基于現(xiàn)有內(nèi)容創(chuàng)建新的用戶界面類型。UIKit中的容器視圖控制器的例子包括UINavigationController,UITabBarController和UISplitViewController,所有這些都方便您的用戶界面的不同部分之間的導(dǎo)航。
設(shè)計(jì)自定義容器視圖控制器
幾乎在任何情況下,容器視圖控制器都像其他任何內(nèi)容視圖控制器一樣管理根視圖和一些內(nèi)容。區(qū)別在于容器視圖控制器從其他視圖控制器獲取其內(nèi)容的一部分。它獲取的內(nèi)容僅限于其他視圖控制器的視圖,它嵌入在其自己的視圖層次結(jié)構(gòu)中。容器視圖控制器設(shè)置任何嵌入視圖的大小和位置,但原始視圖控制器仍然管理這些視圖內(nèi)的內(nèi)容。
在設(shè)計(jì)自己的容器視圖控制器時(shí),請(qǐng)始終了解容器和包含的視圖控制器之間的關(guān)系。視圖控制器的關(guān)系可以幫助告知他們的內(nèi)容應(yīng)該如何顯示在屏幕上,以及你的容器如何在內(nèi)部管理它們。在設(shè)計(jì)過程中,問自己以下問題:
1 .容器的作用是什么?它的孩子扮演什么樣的角色?
2.多少個(gè)孩子同時(shí)顯示?
3.兄弟視圖控制器之間有什么關(guān)系(如果有的話)?
4.子視圖控制器如何添加到容器或從容器中移除?
5.孩子的大小或位置能改變嗎?這些變化在什么情況下發(fā)生?
6.容器是否提供任何裝飾或?qū)Ш较嚓P(guān)的視圖?
7.集裝箱和子公司之間需要什么樣的溝通?容器是否需要向小孩報(bào)告特定事件,而不是由UIViewController班級(jí)定義的標(biāo)準(zhǔn)事件?
8.容器的外觀是否可以用不同的方式配置?如果是這樣,怎么樣?
在定義了各種對(duì)象的角色之后,容器視圖控制器的實(shí)現(xiàn)相對(duì)簡(jiǎn)單。UIKit唯一的要求就是在容器視圖控制器和任何子視圖控制器之間建立正式的父子關(guān)系。親子關(guān)系確保孩子們收到任何相關(guān)的系統(tǒng)消息。除此之外,大部分實(shí)際工作都發(fā)生在包含視圖的布局和管理過程中,對(duì)于每個(gè)容器來說都是不同的。您可以將視圖放置在容器的內(nèi)容區(qū)域的任何位置,然后根據(jù)需要調(diào)整視圖的大小。您還可以將自定義視圖添加到視圖層次結(jié)構(gòu)中,以提供修飾或輔助導(dǎo)航。
示例:導(dǎo)航控制器
UINavigationController對(duì)象通過分層數(shù)據(jù)集支持導(dǎo)航。導(dǎo)航界面一次顯示一個(gè)子視圖控制器。界面頂部的導(dǎo)航欄顯示數(shù)據(jù)層次結(jié)構(gòu)中的當(dāng)前位置,并顯示后退按鈕以向后移動(dòng)一個(gè)級(jí)別。向下導(dǎo)航到數(shù)據(jù)層次結(jié)構(gòu)留給子視圖控制器,可以涉及使用表或按鈕。
視圖控制器之間的導(dǎo)航由導(dǎo)航控制器及其子節(jié)點(diǎn)聯(lián)合管理。當(dāng)用戶與子視圖控制器的按鈕或表格行交互時(shí),孩子要求導(dǎo)航控制器將新的視圖控制器推入視圖。孩子處理新的視圖控制器的內(nèi)容的配置,但導(dǎo)航控制器管理過渡動(dòng)畫。導(dǎo)航控制器還管理導(dǎo)航欄,該導(dǎo)航欄顯示關(guān)閉最上面的視圖控制器的后退按鈕。
圖5-1顯示了導(dǎo)航控制器及其視圖的結(jié)構(gòu)。大多數(shù)內(nèi)容區(qū)域由最頂層的子視圖控制器填充,只有一小部分被導(dǎo)航欄占用。
在緊湊和常規(guī)的環(huán)境中,導(dǎo)航控制器一次只顯示一個(gè)子視圖控制器。導(dǎo)航控制器調(diào)整其子以適應(yīng)可用空間。
示例:分割視圖控制器
一個(gè)UISplitViewController對(duì)象以主 - 細(xì)節(jié)布局顯示兩個(gè)視圖控制器的內(nèi)容。在這種安排中,一個(gè)視圖控制器(主視圖)的內(nèi)容決定了其他視圖控制器顯示的細(xì)節(jié)。兩個(gè)視圖控制器的可見性是可配置的,但也受當(dāng)前環(huán)境的支配。在規(guī)則的水平環(huán)境中,分割視圖控制器可以同時(shí)顯示兩個(gè)子視圖控制器,也可以隱藏主控并根據(jù)需要顯示。在緊湊的環(huán)境中,分割視圖控制器一次只顯示一個(gè)視圖控制器。
圖5-2顯示了在一個(gè)常規(guī)的水平環(huán)境中的分割視圖界面及其視圖的結(jié)構(gòu)。分割視圖控制器本身只有默認(rèn)的容器視圖。在這個(gè)例子中,兩個(gè)子視圖是并排顯示的。子視圖的大小是可配置的,主視圖的可見性也是可配置的。
在界面構(gòu)建器中配置容器
要在設(shè)計(jì)時(shí)創(chuàng)建父子容器關(guān)系,請(qǐng)將容器視圖對(duì)象添加到故事板場(chǎng)景中,如圖5-3所示。容器視圖對(duì)象是代表子視圖控制器內(nèi)容的占位符對(duì)象。使用該視圖來調(diào)整和定位與容器中其他視圖相關(guān)的子視圖。
當(dāng)您使用一個(gè)或多個(gè)容器視圖加載視圖控制器時(shí),Interface Builder還會(huì)加載與這些視圖關(guān)聯(lián)的子視圖控制器。孩子必須與父母同時(shí)實(shí)例化,以便建立適當(dāng)?shù)挠H子關(guān)系。
如果您不使用Interface Builder設(shè)置父 - 子容器關(guān)系,則必須通過將每個(gè)子項(xiàng)添加到容器視圖控制器來以編程方式創(chuàng)建這些關(guān)系,如將子視圖控制器添加到您的內(nèi)容中所述。
實(shí)現(xiàn)自定義容器視圖控制器
要實(shí)現(xiàn)一個(gè)容器視圖控制器,你必須建立你的視圖控制器和它的子視圖控制器之間的關(guān)系。在嘗試管理任何子視圖控制器的視圖之前,建立這些父子關(guān)系是必需的。這樣做讓UIKit知道你的視圖控制器正在管理孩子的大小和位置。您可以在Interface Builder中創(chuàng)建這些關(guān)系,或以編程方式創(chuàng)建它們。以編程方式創(chuàng)建父子關(guān)系時(shí),您明確地添加和刪除子視圖控制器作為視圖控制器設(shè)置的一部分。
將子視圖控制器添加到您的內(nèi)容
要以編程方式將子視圖控制器合并到內(nèi)容中,請(qǐng)執(zhí)行以下操作,在相關(guān)的視圖控制器之間創(chuàng)建父子關(guān)系:
調(diào)用addChildViewController:你的容器視圖控制器的方法。
這個(gè)方法告訴UIKit你的容器視圖控制器現(xiàn)在正在管理子視圖控制器的視圖。
將孩子的根視圖添加到容器的視圖層次結(jié)構(gòu)中。
一定要記住設(shè)置孩子框架的大小和位置,作為這個(gè)過程的一部分。
添加任何約束來管理子視圖的大小和位置。
調(diào)用didMoveToParentViewController:子視圖控制器的方法。
清單5-1展示了一個(gè)容器如何在其容器中嵌入一個(gè)子視圖控制器。建立父子關(guān)系后,容器設(shè)置其子的框架,并將子視圖添加到自己的視圖層次結(jié)構(gòu)中。設(shè)置子視圖的框架大小很重要,并確保視圖在容器中正確顯示。在添加視圖后,容器調(diào)用didMoveToParentViewController:子視圖的方法,使子視圖控制器有機(jī)會(huì)響應(yīng)視圖所有權(quán)的更改。
清單5-1將一個(gè)子視圖控制器添加到一個(gè)容器
- (void) displayContentController: (UIViewController*) content { [self addChildViewController:content]; content.view.frame = [self frameForContentController]; [self.view addSubview:self.currentClientView]; [content didMoveToParentViewController:self]; }
在前面的例子中,注意你只調(diào)用didMoveToParentViewController:子方法。那是因?yàn)樵摲椒槟鉧ddChildViewController:調(diào)用孩子的willMoveToParentViewController:方法。您必須didMoveToParentViewController:自己調(diào)用方法的原因是,只有在將子視圖嵌入到容器的視圖層次結(jié)構(gòu)中之后,方法才能被調(diào)用。
使用自動(dòng)布局時(shí),在將子對(duì)象添加到容器的視圖層次結(jié)構(gòu)后,在容器和子對(duì)象之間設(shè)置約束。你的約束應(yīng)該只影響孩子的根視圖的大小和位置。請(qǐng)勿更改子視圖層次結(jié)構(gòu)中的根視圖或任何其他視圖的內(nèi)容。
刪除子視圖控制器
要從內(nèi)容中刪除子視圖控制器,請(qǐng)通過執(zhí)行以下操作來刪除視圖控制器之間的父子關(guān)系:
willMoveToParentViewController:用值 調(diào)用孩子的方法nil。
刪除您使用該子視圖的配置的任何約束。
從容器的視圖層次結(jié)構(gòu)中移除孩子的根視圖。
調(diào)用孩子的removeFromParentViewController方法來完成親子關(guān)系的結(jié)束。
刪除子視圖控制器會(huì)永久切斷父級(jí)和子級(jí)之間的關(guān)系。只有當(dāng)您不再需要引用子視圖控制器時(shí),才能移除子視圖控制器。例如,當(dāng)新導(dǎo)航控制器被推入導(dǎo)航堆棧時(shí),導(dǎo)航控制器不會(huì)移除其當(dāng)前的子視圖控制器。只有當(dāng)它們從堆棧中彈出時(shí)才會(huì)被刪除。
清單5-2顯示了如何從容器中刪除子視圖控制器。willMoveToParentViewController:使用該值調(diào)用該方法nil使子視圖控制器有機(jī)會(huì)為更改做準(zhǔn)備。該removeFromParentViewController方法還調(diào)用孩子的didMoveToParentViewController:方法,傳遞該方法的值nil。設(shè)置父視圖控制器以nil完成從容器中刪除子視圖。
清單5-2從容器中刪除一個(gè)子視圖控制器
- (void) hideContentController: (UIViewController*) content { [content willMoveToParentViewController:nil]; [content.view removeFromSuperview]; [content removeFromParentViewController]; }
子視圖控制器之間的過渡
當(dāng)您想要用另一個(gè)子視圖控制器替換動(dòng)畫時(shí),將子視圖控制器的添加和刪除合并到轉(zhuǎn)換動(dòng)畫過程中。在動(dòng)畫之前,確保兩個(gè)子視圖控制器都是你的內(nèi)容的一部分,但讓當(dāng)前的孩子知道它即將消失。在您的動(dòng)畫中,將新的孩子的視圖移動(dòng)到位并移除舊的孩子的視圖。完成動(dòng)畫后,完成子視圖控制器的移除。
清單5-3顯示了如何使用過渡動(dòng)畫將一個(gè)子視圖控制器交換為另一個(gè)子視圖控制器的示例。在這個(gè)例子中,新的視圖控制器被動(dòng)畫為現(xiàn)有的子視圖控制器當(dāng)前占用的矩形,該控制器被移出屏幕。動(dòng)畫完成后,完成塊從容器中刪除子視圖控制器。在這個(gè)例子中,該transitionFromViewController:toViewController:duration:options:animations:completion:方法自動(dòng)更新容器的視圖層次,所以你不需要自己添加和刪除視圖。
清單5-3兩個(gè)子視圖控制器之間的轉(zhuǎn)換
- (void)cycleFromViewController: (UIViewController*) oldVC toViewController: (UIViewController*) newVC { // Prepare the two view controllers for the change. [oldVC willMoveToParentViewController:nil]; [self addChildViewController:newVC]; // Get the start frame of the new view controller and the end frame // for the old view controller. Both rectangles are offscreen. newVC.view.frame = [self newViewStartFrame]; CGRect endFrame = [self oldViewEndFrame]; // Queue up the transition animation. [self transitionFromViewController: oldVC toViewController: newVC duration: 0.25 options:0 animations:^{ // Animate the views to their final positions. newVC.view.frame = oldVC.view.frame; oldVC.view.frame = endFrame; } completion:^(BOOL finished) { // Remove the old view controller and send the final // notification to the new view controller. [oldVC removeFromParentViewController]; [newVC didMoveToParentViewController:self]; }]; }
管理兒童的外觀更新
在將容器添加到容器后,容器會(huì)自動(dòng)將外觀相關(guān)的消息轉(zhuǎn)發(fā)給子容器。這通常是您想要的行為,因?yàn)樗_保所有事件都能正確發(fā)送。但是,有時(shí)默認(rèn)行為可能會(huì)以對(duì)您的容器無意義的順序發(fā)送這些事件。例如,如果多個(gè)孩子同時(shí)改變其視圖狀態(tài),則可能需要合并這些更改,以使外觀回調(diào)都以更合理的順序同時(shí)發(fā)生。
為了接管外觀回調(diào)的責(zé)任,重寫shouldAutomaticallyForwardAppearanceMethods容器視圖控制器中的方法并返回NO,如清單5-4所示。返回NO讓UIKit知道你的容器視圖控制器通知其子的外觀變化。
清單5-4禁用自動(dòng)外觀轉(zhuǎn)發(fā)
- (BOOL) shouldAutomaticallyForwardAppearanceMethods { return NO; }
當(dāng)出現(xiàn)外觀轉(zhuǎn)換時(shí),根據(jù)需要調(diào)用子對(duì)象beginAppearanceTransition:animated:或endAppearanceTransition方法。例如,如果您的容器有一個(gè)由child屬性引用的單個(gè)子項(xiàng),那么您的容器會(huì)將這些消息轉(zhuǎn)發(fā)給子項(xiàng),如清單5-5所示。
清單5-5當(dāng)容器出現(xiàn)或消失時(shí)轉(zhuǎn)發(fā)外觀消息
-(void) viewWillAppear:(BOOL)animated { [self.child beginAppearanceTransition: YES animated: animated]; } -(void) viewDidAppear:(BOOL)animated { [self.child endAppearanceTransition]; } -(void) viewWillDisappear:(BOOL)animated { [self.child beginAppearanceTransition: NO animated: animated]; } -(void) viewDidDisappear:(BOOL)animated { [self.child endAppearanceTransition]; }
建立一個(gè)容器視圖控制器的建議
設(shè)計(jì),開發(fā)和測(cè)試新的容器視圖控制器需要時(shí)間。雖然個(gè)人行為是直截了當(dāng)?shù)模麄€(gè)控制者可能相當(dāng)復(fù)雜。在實(shí)現(xiàn)自己的容器類時(shí),請(qǐng)考慮以下提示:
只訪問子視圖控制器的根視圖。一個(gè)容器只能訪問每個(gè)孩子的根視圖,也就是孩子view屬性返回的視圖。它不應(yīng)該訪問任何孩子的其他意見。
子視圖控制器應(yīng)該對(duì)其容器有最少的了解。子視圖控制器應(yīng)該關(guān)注自己的內(nèi)容。如果容器允許其行為受到孩子的影響,則應(yīng)該使用委托設(shè)計(jì)模式來管理這些交互。
首先使用常規(guī)視圖設(shè)計(jì)您的容器。使用常規(guī)視圖(而不是來自子視圖控制器的視圖)使您有機(jī)會(huì)在簡(jiǎn)化的環(huán)境中測(cè)試布局約束和動(dòng)畫過渡。當(dāng)常規(guī)視圖按預(yù)期工作時(shí),將它們交換為您的子視圖控制器的視圖。
將控制委派給子視圖控制器
容器視圖控制器可以將其自身外觀的某些方面委托給其一個(gè)或多個(gè)子級(jí)。您可以通過以下方式委托控制:
讓一個(gè)子視圖控制器確定狀態(tài)欄的樣式。要委派狀態(tài)欄外觀小孩,覆蓋的一個(gè)或兩個(gè)childViewControllerForStatusBarStyle,并childViewControllerForStatusBarHidden在你的容器視圖控制器的方法。
讓孩子指定自己喜歡的尺寸。具有靈活布局的容器可以使用孩子自己的preferredContentSize財(cái)產(chǎn)來幫助確定孩子的大小。
感謝各位的閱讀!關(guān)于“iOS如何實(shí)現(xiàn)容器視圖控制器”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!