UIViewController containment

iOS 5之前viewcontroller容器是不推薦使用的,這個(gè)時(shí)期的viewcontroller的任務(wù)是管理一個(gè)充滿屏幕的view。從ios5 之后viewcontroller的任務(wù)即演變?yōu)楣芾碜约旱膙iew。那么究竟是什么原因?qū)е虏豢梢詫iew controller的view當(dāng)做子view來用呢

子viewcontroller的view作為子view

眾所周知,UIWindow是app的根view,即是屏幕旋轉(zhuǎn)即layout初始化信息源起的地方。由上圖所知,子view controller的view是被插入rootviewcontroller的view層級(jí)中的,所以layout信息是不會(huì)觸達(dá)這個(gè)子view controller的(比如 viewWillAppear)

ios5之前的自定義viewcontroller需要維護(hù)子controller的引用,并在自己收到各view事件之后手動(dòng)觸發(fā)各子controller的view事件方法, iOS 5之后不需要這樣做,但各子view controller的viewwillappear等方法的調(diào)用時(shí)機(jī)規(guī)則可能跟獨(dú)立的Viewcontroller不太一樣。

尋找當(dāng)前地點(diǎn)對(duì)應(yīng)的地球另一面的地點(diǎn)

移動(dòng)拿著鏟子的人,地圖會(huì)告訴你地球另一面的地點(diǎn)是哪里,點(diǎn)擊雷達(dá)按鈕,地圖會(huì)輕彈并顯示地點(diǎn)的名字。

上圖中有兩個(gè)map view controller,他們每個(gè)都可以單獨(dú)處理拖拽,注釋和更新地圖。輕彈它們會(huì)出現(xiàn)兩個(gè)新的viewcontroller,這些view controller會(huì)呈現(xiàn)位置的詳細(xì)文字描述。且所有這些都包含在一個(gè)父viewcontroller中,持有子view controller的View并確保布局轉(zhuǎn)屏運(yùn)行正常。

viewcontroller代碼

_startMapViewController作為子controller被添加,這會(huì)導(dǎo)致子controller的willMoveToParentViewController方法被調(diào)用,其view被添加進(jìn)第一個(gè)容器view中,并顯示通知其當(dāng)前擁有parent controller(調(diào)用didMoveToParentViewController),_startGeoViewController初始化但并未添加進(jìn)view層級(jí)

viewcontroller之間的切換

基于細(xì)粒度的viewcontroller包含api,使得創(chuàng)建及動(dòng)畫的效果可以應(yīng)用在viewcontroller包含的場景中。切換兩個(gè)controller的view的方法如下:(transitionFromViewController:toViewController:(...))

切換controller

在添加 toController為子controller時(shí),先通知fromController它將被移除,如果它是包含view層級(jí)中的一員,則會(huì)調(diào)用其viewWillDisappear方法

toController會(huì)被通知其新的parentcontroller,并調(diào)用相關(guān)view事件方法。接著移除fromController

這個(gè)transition API方便地將舊view切換出去并為新view騰出空間,然而如果你想自定義切換效果,并只希望同一時(shí)刻只出現(xiàn)一個(gè)view,則需要對(duì)舊View調(diào)用 removefromsuperview,并對(duì)新view調(diào)用 addSubView。如果方法調(diào)用順序出錯(cuò)會(huì)得到UIViewControllerHierarchyInconsistency的警告,比如在添加view之前即調(diào)用didMoveToParentViewController

為了使用UIViewAnimationOptionTransitionFlipFromTop動(dòng)畫,需要將子view添加為兩個(gè)容器view的子view,而不是根controller的view,否則動(dòng)畫會(huì)是整個(gè)root view的效果。

父子controller之間的交互

它們之間只能通過暴露的api進(jìn)行交互,且父controller需要負(fù)責(zé)layout子controller的view。父controller不應(yīng)當(dāng)修改子controller的view

custom container view controllers

任何時(shí)候子controller的view顯示在容器的view層次中的時(shí)候,容器controller都需要與子controller建立聯(lián)系并保證將所有適當(dāng)?shù)腸ontroller事件發(fā)送給子controller。

容器controller的view層次包含其他controller的view

容器制定規(guī)則,子controller需要遵守;容器決定子controller的內(nèi)容何時(shí)出現(xiàn)在其view層次上,同時(shí)決定了其出現(xiàn)的位置和大小。必要情況下,容器controller也可以暴露屬性和方法以供外界操作。

以navigationcontroller為例 ,當(dāng)controller從棧上彈出或者入棧時(shí),可以做動(dòng)態(tài)切換

需要注意的是,shouldAutomaticallyForwardAppearanceMethods屬性用來標(biāo)識(shí)是否將容器controller的appearance相關(guān)的回調(diào),直接傳遞給子controller。如果是NO,則容器controller負(fù)責(zé)告訴子controller何時(shí)view appear/disappear(通過調(diào)用子controller的beginAppearanceTransition:animated: 和 endAppearanceTransition方法來實(shí)現(xiàn)),不要直接調(diào)用子controller的view will/did appear/disappear方法。

在準(zhǔn)備將controller添加進(jìn)parentcontroller或者移除時(shí),需要在動(dòng)作之前操作willmovetoparentviewcontroller,之后操作didmovetocontroller,addchildviewcontroller自動(dòng)調(diào)用willmoveto,didmoveto需要在出現(xiàn)的transition結(jié)束之后(或者如果沒有transition則馬上)馬上調(diào)用, removefromparentviewcontroller自動(dòng)調(diào)用didmovetocontroller,willmoveto需要在remove之前調(diào)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容