iOS 自定義轉場動畫

簡介

在日常開發中動畫是必不可少的,蘋果也為iOS開發提供了很多好的動畫效果,作為iOS開發者自然需要對動畫有所了解。在這些動畫中,有一種動畫是用于一個場景轉換到另一個場景的過渡動畫,我們稱之為轉場動畫,本文主要內容是關于轉場動畫的。

轉場,顧名思義是場景的轉換,即界面由一個場景轉換到另一個場景。在iOS中可以分為視圖控制器轉換視圖的轉換兩個層次,本文的主要結構如下:

  • 轉場動畫簡介
  • 視圖控制器轉場的實現機制 -- 五大協議
  • 視圖轉場的實現 -- CATransition

視圖控制器轉場 -- View Controller Transition

在iOS 7之前,系統已經提供了一些默認的視圖控制器轉場動畫,但是這些動畫是完全由系統實現的,不能進行自定義。在iOS 7的時候,系統開放了部分API,使得自定義轉場動畫成為現實。

自定義轉場動畫相關的API主要包括五個協議,下面分別介紹下:

  • 轉場代理
  • 轉場上下文環境協議
  • 動畫控制器協議
  • 交互控制器協議
  • 轉場協調器協議

1、轉場代理

視圖控制器中的視圖顯示在屏幕上有兩種方式:1、內嵌在容器中,例如UINavigationController、UITabBarController、 2、模態彈出,即Present/dismiss

對于這些方式,系統在對應的代理協議中都提供了關于轉場動畫的相關方法,下面逐個分析下:

1.1 導航欄代理 - UINavigationControllerDelegate

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

該方法返回一個遵守UIViewControllerAnimatedTransitioning協議的可選對象,該協議即為動畫控制器協議,在后文會專門介紹,這里先做個簡介。我們可以在遵守該協議的類中進行轉場動畫的設計,如果返回的對象為nil,則保持系統動畫,不會使用自定義動畫。

參數中,operation是一個枚舉類型,其case為 .none、.push、.pop;fromVC表示push/pop動作發生時顯示的ViewController,即動畫之前的ViewController,toVC表示動畫結束后的ViewController,例如push動作由 A -> B,則fromVC為A,toVC為B,當發生pop動作 B -> A時,fromVC為B,toVC為A。

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

該方法返回一個遵守UIViewControllerInteractiveTransitioning協議的可選對象,該協議對象為一個可交互的轉場對象,即交互控制協議對象,該對象定義了轉場動畫的交互行為。

1.2 模態的代理 - UIViewControllerTransitioningDelegate

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

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

這兩個方法均返回一個遵守UIViewControllerAnimatedTransitioning協議的可選對象,用于在模態彈出時,返回自定義轉場動畫的對象。與導航欄有所不同的是,模態彈出分為了 present 和 dismiss 兩個方法。

在present方法中,presented表示被present的ViewController,source表示調用方法的ViewController,presenting可以與source相同,也可以不相同,當source作為一個childViewController時,presenting為source的父控制器,否則presenting與source相同

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

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

與設置動畫控制器的方法一樣,在設置交互控制器時,模態方式也分為了 present 和 dismiss 兩個方法,分別用來設置present 和 dismiss時的交互行為。

1.3 tabbar的轉場代理

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

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

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

2、轉場上下文

轉場上下文是一個遵守UIViewControllerContextTransitioning協議的對象,該對象由系統自動創建,無需我們進行管理。UIViewControllerContextTransitioning協議包含如下API:

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

containerView是一個容器,轉場動畫前后的View以及要添加的動畫視圖都是添加在這個容器中的。事實上,該容器的類型是UIViewControllerWrapperView,無論是自定義轉場,還是系統定義的轉場,最終都是添加在該view上,并且作為一個全局的上下文,該view只存在一份,因此需要合理管理其子視圖。

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

根據UITransitionContextViewControllerKeyfromto獲取轉場前后的ViewController,并且與上文所述fromVC和toVC一致,轉場前后的ViewController是可逆的。例如push時 A -> B,則A是 fromVC, B是 toVC;在pop回去是二者的位置則發生了對調。

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

在iOS 7及之前,我們只能通過獲取到轉場前后的ViewController,進而獲取其view來獲取轉場前后的視圖,但是在iOS 8及以后,我們可以直接獲取轉場前后的View。

var transitionWasCancelled: Bool { get }

該屬性為一個只讀的計算屬性,表示轉場是否被取消。當轉場動畫為一個可交互式動畫時,動畫進行過程中可以手動觸發取消,如果取消了則該屬性為true,而如果沒有取消,則為false,對于一個非交互式動畫,則該值一直為false。

func completeTransition(_ didComplete: Bool)

當轉場動畫完成或者被取消時,調用該方法。

3、動畫控制器

動畫控制器協議定義了一系列API,用以配置實現轉場動畫。我們創建一個自己的類,并遵守該協議,然后通過轉場代理將自定義動畫的Trasnsition返回給系統。

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

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

該方法返回一個時長,在該方法中定義轉場動畫持續的時間

func animateTransition(using transitionContext: UIViewControllerContextTransitioning)

在該方法中,定義轉場要做的動畫。

4、交互控制器

交互控制器協議是用來配置轉場動畫的交互事件的,實際的動畫依然由動畫控制器來完成。系統定義了UIViewControllerInteractiveTransitioning協議,但是在實際使用時,我們不會直接遵守該協議,而是繼承UIPercentDrivenInteractiveTransition類。

UIPercentDrivenInteractiveTransition是系統提供的類,根據蘋果官方文檔的解釋,創建一個交互式動畫對象最簡單的方式就是繼承該類,如下圖所示。

圖片

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

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

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

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

open func cancel()  // 取消動畫

open func finish()  // 完成動畫

// 上訴三個方法對應UIViewControllerContextTransitioning協議中的 updateInteractiveTransition、cancelInteractiveTransition()、finishInteractiveTransition()方法

5、轉場協調器

轉場協調器用于幫助做一些輔助動畫,由系統進行創建,我們通過UIViewController的分類中的屬性即可獲取,代碼如圖:

圖片

在UIViewControllerTransitionCoordinator中定義了如下API

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

在該方法中添加動畫,當轉場動畫執行完畢后,會繼續執行animation閉包中的動畫,而如果使用UIView.animate(withDuration的方式添加動畫,則會在轉場動畫執行時,動畫就已經執行完畢。

CATransition

上文介紹了ViewController間的轉場實現機制,在CoreAnimation框架中,還有一個動畫類用來做layer級的轉場,即CATransition。CATransition是作用于CALayer上的,因此需要將CATransition添加到view的layer屬性上。

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

open var type: CATransitionType
圖片

該屬性表示轉場的類型,例如 fade、push、moveIn等,具體效果可參考CATransitionDemo[1]

open var subtype: CATransitionSubtype?
圖片

該屬性表示轉場的方向,但是對于fade這種與方向無關的轉場,該屬性是沒有效果的。

/* 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

這兩個屬性分別表示開始時的進度和結束時的進度,結合父類的duration屬性,可以控制動畫的開始和結束為止。需要注意的是,這兩個屬性的值為[0, 1],并且 startProgress要小于 endProgress。

總結

本文主要介紹了轉場動畫的實現流程,主要有如下兩部分內容:

  • 1、ViewController的轉場

  • 2、View的轉場

分別對應轉場的五大協議CATransition。本文只是介紹了相關的API使用,具體Demo可參照網上的CATransitionDemo[2]和VCTransitionsLibrary[3]

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容