關(guān)于iOS的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的實(shí)現(xiàn):
轉(zhuǎn)場(chǎng)動(dòng)畫(huà)實(shí)際上就是對(duì)View添加的轉(zhuǎn)場(chǎng)效果,在CATransiton就已經(jīng)給我們提供了豐富的事例
所以ViewController控制器之間的轉(zhuǎn)場(chǎng),其實(shí)還是對(duì)VC.view的操作,不過(guò)因?yàn)閂iewController的層級(jí)更復(fù)雜一些,所以需要先進(jìn)行一些其他的操作。
在實(shí)現(xiàn)自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà)之前,我們需要先了解實(shí)現(xiàn)ViewController轉(zhuǎn)場(chǎng)動(dòng)畫(huà)執(zhí)行的流程。
整體流程大致可以分為三步:
第一步:調(diào)用系統(tǒng)push/pop或者present/dismiss方法,獲取到VC跳轉(zhuǎn)的代理方法
第二步:在系統(tǒng)跳轉(zhuǎn)代理方法中,提供一個(gè)控制兩個(gè)View的實(shí)例對(duì)象,作為View轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的載體
第三部:實(shí)現(xiàn)自定義動(dòng)畫(huà)(UIViewAnimation或者CAAnimation),并添加到這個(gè)實(shí)例中
接下來(lái)對(duì)這三步進(jìn)行詳細(xì)說(shuō)明:
1.首先實(shí)現(xiàn)第一步,在push/pop時(shí)獲取的到系統(tǒng)執(zhí)行轉(zhuǎn)場(chǎng)的代理方法:
這里先給ViewController添加了一個(gè)分類(lèi)Transition,用來(lái)統(tǒng)一調(diào)用push/present方法。transitionManager是從外部傳進(jìn)來(lái)的實(shí)例對(duì)象,后面會(huì)講到。
在分類(lèi)實(shí)現(xiàn)自定義的跳轉(zhuǎn)方法

從上圖可以看到,在兩個(gè)跳轉(zhuǎn)方法中都設(shè)置了delegate代理對(duì)象為transitionManager。點(diǎn)進(jìn)去查看源碼后,發(fā)現(xiàn)系統(tǒng)給ViewController提供了一個(gè)分類(lèi):UIViewControllerTransitioning

在上圖中可以看到,分類(lèi)中包含了一個(gè)UIViewControllerTransitioningDelegate協(xié)議,這個(gè)協(xié)議就是我們獲取系統(tǒng)push/present代理方法的關(guān)鍵,只要我們給transitioningDelegate屬性設(shè)置代理對(duì)象,就能獲取到系統(tǒng)跳轉(zhuǎn)的代理方法。上圖中只給出了ViewController的情況,如果是NavigationController類(lèi),協(xié)議就是UINavigationControllerDelegate,需要給UINavigationControllerDelegate設(shè)置代理對(duì)象。
下面我們新建一個(gè)繼承自NSObject的類(lèi):TransitionManager類(lèi),上面transitionManager就是這個(gè)類(lèi)的實(shí)例對(duì)象。并且遵守UINavigationControllerDelegate和UIViewControllerTransitioningDelegate這兩個(gè)協(xié)議。
在TransitionManager中,分別實(shí)現(xiàn)協(xié)議中的中轉(zhuǎn)場(chǎng)代理方法
1.model模態(tài)視圖present/dismiss方法
2.push/pop視圖方法

這樣第一步我們就獲取到了VC跳轉(zhuǎn)的代理方法。
2.接著是第二步:獲取載體實(shí)例
在上面截取的部分代碼中不難發(fā)現(xiàn),在獲取到系統(tǒng)跳轉(zhuǎn)方法以后,我們都返回了一個(gè)transitionContext實(shí)例對(duì)象,這里使用transitionContext對(duì)象來(lái)作為實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)載體實(shí)例對(duì)象。
跟第一步一樣,我們還是要先創(chuàng)建一個(gè)繼承自NSObject的類(lèi):TransitionContext類(lèi),并且遵守了UIViewControllerContextTransitioning這個(gè)協(xié)議,這個(gè)協(xié)議就是我們獲取載體實(shí)例的關(guān)鍵。

遵守了這個(gè)協(xié)議以后,在.m文件中實(shí)現(xiàn)下面的系統(tǒng)方法,就能獲取到transitionContext對(duì)象作為執(zhí)行view轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的載體,我們還給這個(gè)類(lèi)添加了一個(gè)block屬性,用于回調(diào)獲取到的這個(gè)載體實(shí)例。

接下來(lái)就是最后一步了。
3.第三步:實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
在第一步的跳轉(zhuǎn)代理方法中,我們返回了一個(gè)transitionContext對(duì)象,其實(shí)這個(gè)對(duì)象就是由第二步的block回調(diào)得到?,F(xiàn)在將使用這個(gè)對(duì)象來(lái)實(shí)現(xiàn)我們的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)。使用懶加載初始化TransitionManager的中定義的TransitionContext實(shí)例對(duì)象

在TransitionManager的.h文件中,還定義了setToAnimation:和setBackAnimation:兩個(gè)方法。在這兩個(gè)方法中來(lái)實(shí)現(xiàn)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的具體動(dòng)畫(huà)代碼。
但是直接在TransitionManager中編寫(xiě),會(huì)讓TransitionManager變得十分臃腫,所以對(duì)于每一個(gè)具體轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的實(shí)現(xiàn),這里都會(huì)新建一個(gè)繼承自TransitionManager的子類(lèi),來(lái)專(zhuān)門(mén)實(shí)現(xiàn)setBackAnimation和setBackAnimation轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的具體代碼。
項(xiàng)目中創(chuàng)建一個(gè)繼承自TransitionManager的類(lèi):CircleSpreadAnimation類(lèi),自定義一個(gè)實(shí)例化方法。

實(shí)現(xiàn)setToAnimation和setBackAnimation。

這里代碼較多,只貼出了一少部分。接下來(lái)就是如何調(diào)用
這里定義了兩個(gè)控制器CircleSpreadFromViewController、CircleSpreadToViewController,在CircleSpreadFromViewController傳入了點(diǎn)擊位置、動(dòng)畫(huà)初始半徑和動(dòng)畫(huà)持續(xù)時(shí)間,一個(gè)完整的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)就完成了。

使用上面的系統(tǒng)協(xié)議,基本上就能實(shí)現(xiàn)自定義轉(zhuǎn)場(chǎng)動(dòng)畫(huà),這里是代碼部分。
除此之外,在第一步獲取系統(tǒng)跳轉(zhuǎn)時(shí),也可以使用runtime的Method_ExchangeImplementations,替換系統(tǒng)push/present方法。后面的第二、三步思路不變。