iOS 自定義轉(zhuǎn)場動畫

簡介

在日常開發(fā)中動畫是必不可少的氓涣,蘋果也為iOS開發(fā)提供了很多好的動畫效果塘秦,作為iOS開發(fā)者自然需要對動畫有所了解定踱。在這些動畫中筷狼,有一種動畫是用于一個場景轉(zhuǎn)換到另一個場景的過渡動畫瓶籽,我們稱之為轉(zhuǎn)場動畫,本文主要內(nèi)容是關(guān)于轉(zhuǎn)場動畫的埂材。

轉(zhuǎn)場塑顺,顧名思義是場景的轉(zhuǎn)換,即界面由一個場景轉(zhuǎn)換到另一個場景俏险。在iOS中可以分為視圖控制器轉(zhuǎn)換視圖的轉(zhuǎn)換兩個層次严拒,本文的主要結(jié)構(gòu)如下:

  • 轉(zhuǎn)場動畫簡介
  • 視圖控制器轉(zhuǎn)場的實現(xiàn)機制 -- 五大協(xié)議
  • 視圖轉(zhuǎn)場的實現(xiàn) -- CATransition

視圖控制器轉(zhuǎn)場 -- View Controller Transition

在iOS 7之前,系統(tǒng)已經(jīng)提供了一些默認的視圖控制器轉(zhuǎn)場動畫竖独,但是這些動畫是完全由系統(tǒng)實現(xiàn)的裤唠,不能進行自定義。在iOS 7的時候,系統(tǒng)開放了部分API诡必,使得自定義轉(zhuǎn)場動畫成為現(xiàn)實个从。

自定義轉(zhuǎn)場動畫相關(guān)的API主要包括五個協(xié)議,下面分別介紹下:

  • 轉(zhuǎn)場代理
  • 轉(zhuǎn)場上下文環(huán)境協(xié)議
  • 動畫控制器協(xié)議
  • 交互控制器協(xié)議
  • 轉(zhuǎn)場協(xié)調(diào)器協(xié)議

1劈彪、轉(zhuǎn)場代理

視圖控制器中的視圖顯示在屏幕上有兩種方式:1、內(nèi)嵌在容器中顶猜,例如UINavigationController沧奴、UITabBarController、 2长窄、模態(tài)彈出滔吠,即Present/dismiss

對于這些方式,系統(tǒng)在對應(yīng)的代理協(xié)議中都提供了關(guān)于轉(zhuǎn)場動畫的相關(guān)方法挠日,下面逐個分析下:

1.1 導(dǎo)航欄代理 - UINavigationControllerDelegate

optional func navigationController(_ navigationController: UINavigationController, 
            animationControllerFor operation: UINavigationController.Operation, 
                              from fromVC: UIViewController, 
                                to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?

該方法返回一個遵守UIViewControllerAnimatedTransitioning協(xié)議的可選對象疮绷,該協(xié)議即為動畫控制器協(xié)議,在后文會專門介紹嚣潜,這里先做個簡介冬骚。我們可以在遵守該協(xié)議的類中進行轉(zhuǎn)場動畫的設(shè)計,如果返回的對象為nil,則保持系統(tǒng)動畫只冻,不會使用自定義動畫庇麦。

參數(shù)中,operation是一個枚舉類型喜德,其case為 .none山橄、.push、.pop舍悯;fromVC表示push/pop動作發(fā)生時顯示的ViewController航棱,即動畫之前的ViewController,toVC表示動畫結(jié)束后的ViewController萌衬,例如push動作由 A -> B饮醇,則fromVC為A,toVC為B奄薇,當發(fā)生pop動作 B -> A時驳阎,fromVC為B,toVC為A馁蒂。

optional func navigationController(_ navigationController: UINavigationController, 
          interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?

該方法返回一個遵守UIViewControllerInteractiveTransitioning協(xié)議的可選對象呵晚,該協(xié)議對象為一個可交互的轉(zhuǎn)場對象,即交互控制協(xié)議對象沫屡,該對象定義了轉(zhuǎn)場動畫的交互行為饵隙。

1.2 模態(tài)的代理 - UIViewControllerTransitioningDelegate

optional func animationController(forPresented presented: UIViewController, 
                       presenting: UIViewController, 
                           source: UIViewController) -> UIViewControllerAnimatedTransitioning?

optional func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?

這兩個方法均返回一個遵守UIViewControllerAnimatedTransitioning協(xié)議的可選對象,用于在模態(tài)彈出時沮脖,返回自定義轉(zhuǎn)場動畫的對象金矛。與導(dǎo)航欄有所不同的是,模態(tài)彈出分為了 present 和 dismiss 兩個方法勺届。

在present方法中驶俊,presented表示被present的ViewController,source表示調(diào)用方法的ViewController免姿,presenting可以與source相同饼酿,也可以不相同,當source作為一個childViewController時胚膊,presenting為source的父控制器故俐,否則presenting與source相同

optional func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?

optional func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?

與設(shè)置動畫控制器的方法一樣紊婉,在設(shè)置交互控制器時药版,模態(tài)方式也分為了 present 和 dismiss 兩個方法,分別用來設(shè)置present 和 dismiss時的交互行為喻犁。

1.3 tabbar的轉(zhuǎn)場代理

optional func tabBarController(_ tabBarController: UITabBarController, 
animationControllerForTransitionFrom fromVC: UIViewController, 
                            to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?

optional func tabBarController(_ tabBarController: UITabBarController, 
      interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?

與上文所述一致槽片,這兩個方法分別返回動畫控制器和交互控制器何缓。

2、轉(zhuǎn)場上下文

轉(zhuǎn)場上下文是一個遵守UIViewControllerContextTransitioning協(xié)議的對象筐乳,該對象由系統(tǒng)自動創(chuàng)建歌殃,無需我們進行管理乔妈。UIViewControllerContextTransitioning協(xié)議包含如下API:

@available(iOS 2.0, *) var containerView: UIView { get }

containerView是一個容器蝙云,轉(zhuǎn)場動畫前后的View以及要添加的動畫視圖都是添加在這個容器中的。事實上路召,該容器的類型是UIViewControllerWrapperView勃刨,無論是自定義轉(zhuǎn)場,還是系統(tǒng)定義的轉(zhuǎn)場股淡,最終都是添加在該view上身隐,并且作為一個全局的上下文,該view只存在一份唯灵,因此需要合理管理其子視圖贾铝。

@available(iOS 2.0, *) func viewController(forKey key: UITransitionContextViewControllerKey) -> UIViewController?

根據(jù)UITransitionContextViewControllerKeyfromto獲取轉(zhuǎn)場前后的ViewController,并且與上文所述fromVC和toVC一致埠帕,轉(zhuǎn)場前后的ViewController是可逆的垢揩。例如push時 A -> B,則A是 fromVC, B是 toVC敛瓷;在pop回去是二者的位置則發(fā)生了對調(diào)叁巨。

@available(iOS 8.0, *) func view(forKey key: UITransitionContextViewKey) -> UIView?

在iOS 7及之前,我們只能通過獲取到轉(zhuǎn)場前后的ViewController呐籽,進而獲取其view來獲取轉(zhuǎn)場前后的視圖锋勺,但是在iOS 8及以后,我們可以直接獲取轉(zhuǎn)場前后的View狡蝶。

var transitionWasCancelled: Bool { get }

該屬性為一個只讀的計算屬性庶橱,表示轉(zhuǎn)場是否被取消。當轉(zhuǎn)場動畫為一個可交互式動畫時贪惹,動畫進行過程中可以手動觸發(fā)取消苏章,如果取消了則該屬性為true,而如果沒有取消馍乙,則為false布近,對于一個非交互式動畫,則該值一直為false丝格。

func completeTransition(_ didComplete: Bool)

當轉(zhuǎn)場動畫完成或者被取消時撑瞧,調(diào)用該方法。

3显蝌、動畫控制器

動畫控制器協(xié)議定義了一系列API预伺,用以配置實現(xiàn)轉(zhuǎn)場動畫订咸。我們創(chuàng)建一個自己的類,并遵守該協(xié)議酬诀,然后通過轉(zhuǎn)場代理將自定義動畫的Trasnsition返回給系統(tǒng)脏嚷。

動畫控制器中有兩個主要的API,分別為:

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval

該方法返回一個時長瞒御,在該方法中定義轉(zhuǎn)場動畫持續(xù)的時間

func animateTransition(using transitionContext: UIViewControllerContextTransitioning)

在該方法中父叙,定義轉(zhuǎn)場要做的動畫。

4肴裙、交互控制器

交互控制器協(xié)議是用來配置轉(zhuǎn)場動畫的交互事件的趾唱,實際的動畫依然由動畫控制器來完成。系統(tǒng)定義了UIViewControllerInteractiveTransitioning協(xié)議蜻懦,但是在實際使用時甜癞,我們不會直接遵守該協(xié)議,而是繼承UIPercentDrivenInteractiveTransition類宛乃。

UIPercentDrivenInteractiveTransition是系統(tǒng)提供的類悠咱,根據(jù)蘋果官方文檔的解釋,創(chuàng)建一個交互式動畫對象最簡單的方式就是繼承該類征炼,如下圖所示析既。

該類的API主要有如下幾個:

open var duration: CGFloat { get } // 動畫時長,根據(jù)transitionDuration:的返回值確定

open var percentComplete: CGFloat { get }  // 完成百分比

open func update(_ percentComplete: CGFloat)  // 更新動畫完成百分比

open func cancel()  // 取消動畫

open func finish()  // 完成動畫

// 上訴三個方法對應(yīng)UIViewControllerContextTransitioning協(xié)議中的 updateInteractiveTransition柒室、cancelInteractiveTransition()渡贾、finishInteractiveTransition()方法

5、轉(zhuǎn)場協(xié)調(diào)器

轉(zhuǎn)場協(xié)調(diào)器用于幫助做一些輔助動畫雄右,由系統(tǒng)進行創(chuàng)建空骚,我們通過UIViewController的分類中的屬性即可獲取,代碼如圖:

[圖片上傳失敗...(image-9eed14-1648431789762)]

在UIViewControllerTransitionCoordinator中定義了如下API

func animate(alongsideTransition animation: ((UIViewControllerTransitionCoordinatorContext) -> Void)?, completion: ((UIViewControllerTransitionCoordinatorContext) -> Void)? = nil) -> Bool

在該方法中添加動畫擂仍,當轉(zhuǎn)場動畫執(zhí)行完畢后囤屹,會繼續(xù)執(zhí)行animation閉包中的動畫,而如果使用UIView.animate(withDuration的方式添加動畫逢渔,則會在轉(zhuǎn)場動畫執(zhí)行時肋坚,動畫就已經(jīng)執(zhí)行完畢。

CATransition

上文介紹了ViewController間的轉(zhuǎn)場實現(xiàn)機制肃廓,在CoreAnimation框架中智厌,還有一個動畫類用來做layer級的轉(zhuǎn)場,即CATransition盲赊。CATransition是作用于CALayer上的铣鹏,因此需要將CATransition添加到view的layer屬性上。

CATransition是繼承自CAAnimation的類哀蘑,其自己所包含的屬性由:

open var type: CATransitionType
image.png

該屬性表示轉(zhuǎn)場的類型诚卸,例如 fade葵第、push、moveIn等合溺,具體效果可參考CATransitionDemo[1]

open var subtype: CATransitionSubtype?復(fù)制代碼
image.png

該屬性表示轉(zhuǎn)場的方向卒密,但是對于fade這種與方向無關(guān)的轉(zhuǎn)場,該屬性是沒有效果的棠赛。

/* The amount of progress through to the transition at which to begin
     * and end execution. Legal values are numbers in the range [0,1].
     * `endProgress' must be greater than or equal to `startProgress'.
     * Default values are 0 and 1 respectively. */

open var startProgress: Float

open var endProgress: Float

這兩個屬性分別表示開始時的進度和結(jié)束時的進度哮奇,結(jié)合父類的duration屬性,可以控制動畫的開始和結(jié)束為止恭朗。需要注意的是屏镊,這兩個屬性的值為[0, 1]依疼,并且 startProgress要小于 endProgress痰腮。

總結(jié)

本文主要介紹了轉(zhuǎn)場動畫的實現(xiàn)流程,主要有如下兩部分內(nèi)容:

  • 1律罢、ViewController的轉(zhuǎn)場

  • 2膀值、View的轉(zhuǎn)場

分別對應(yīng)轉(zhuǎn)場的五大協(xié)議CATransition。本文只是介紹了相關(guān)的API使用误辑,具體Demo可參照網(wǎng)上的CATransitionDemo[2]和VCTransitionsLibrary[3]沧踏。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市巾钉,隨后出現(xiàn)的幾起案子翘狱,更是在濱河造成了極大的恐慌,老刑警劉巖砰苍,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件潦匈,死亡現(xiàn)場離奇詭異,居然都是意外死亡赚导,警方通過查閱死者的電腦和手機茬缩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼旧,“玉大人凰锡,你說我怎么就攤上這事∪Π担” “怎么了掂为?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長员串。 經(jīng)常有香客問我勇哗,道長,這世上最難降的妖魔是什么昵济? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任智绸,我火速辦了婚禮野揪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瞧栗。我一直安慰自己斯稳,他們只是感情好,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布迹恐。 她就那樣靜靜地躺著挣惰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪殴边。 梳的紋絲不亂的頭發(fā)上憎茂,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音锤岸,去河邊找鬼竖幔。 笑死,一個胖子當著我的面吹牛是偷,可吹牛的內(nèi)容都是我干的拳氢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蛋铆,長吁一口氣:“原來是場噩夢啊……” “哼馋评!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刺啦,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤留特,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后玛瘸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蜕青,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年捧韵,在試婚紗的時候發(fā)現(xiàn)自己被綠了市咆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡再来,死狀恐怖蒙兰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芒篷,我是刑警寧澤搜变,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站针炉,受9級特大地震影響挠他,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜篡帕,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一殖侵、第九天 我趴在偏房一處隱蔽的房頂上張望贸呢。 院中可真熱鬧,春花似錦拢军、人聲如沸楞陷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽固蛾。三九已至,卻和暖如春度陆,著一層夾襖步出監(jiān)牢的瞬間艾凯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工懂傀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留趾诗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓鸿竖,卻偏偏與公主長得像沧竟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子缚忧,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355

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