天天看點

Custom View Controller Transition Animation iOS自定義VC轉場動畫

Custom View Controller Transition Animation

    • 自定義動畫協定
        • 1. Transition Delegate
        • 2. Animation Controller
        • 3. Transitioning Context
        • 4. Transition Coordinator
    • 自定義動畫執行過程
    • 代碼實作

Transition animation定義了應用程式的View改變時産生的視覺回報。除了UIkit提供的标準轉場樣式,我們也可以使用自定義Transition Animation來實作自己想要的視覺效果。在iOS7之後,蘋果以協定的方式開放了自定義轉場的API, 使得遵守協定的對象都能參與轉場。本文将介紹自定義動畫的相關知識。

自定義動畫協定

1. Transition Delegate

每一個 View Controller 都有一個 transitioningDelegate (UIViewControllerTransitioningDelegate 的對象)

每當要進入或關閉 View Controller 時,UIKit 都會請求其 transitioningDelegate 提供Animation Controller 使用。要将預設動畫替換為您自己的自定義動畫,必須實作 transitioningDelegate,并使其傳回适當的 Animation Controller。

2. Animation Controller

transitioningDelegate 傳回的 Animation Controller (UIViewControllerAnimatedTransitioning 的對象)承擔了轉場動畫的繁重任務。除了Animation Controller,transitioningDelegate還會傳回另外兩種對象:

Interactive Animation Controller:使用觸摸事件或者手勢識别器來驅動自定義動畫,遵循UIViewControllerInteractiveTransitioning協定

Presentation controller:管理着視圖控制器在螢幕上顯示時的呈現樣式,可以自定義呈現樣式。

如果沒有提供Animation Controller,UIKit在VC的modalTransitionStyle屬性中會使用标準的Transition animation。

Custom View Controller Transition Animation iOS自定義VC轉場動畫

3. Transitioning Context

在 Transition animation執行之前,UIKit會構造一個Transitioning Context,用于儲存Transition animation中涉及的所有VC和View的引用,以及轉場資訊,包括動畫是否是互動式。該協定無須手動實作,UIkit會在每次轉場時将其傳遞給Animation Controller。Animation Controller 通過這些資訊來具體實作動畫效果。

Custom View Controller Transition Animation iOS自定義VC轉場動畫

4. Transition Coordinator

UIKit會建立一個Transition Coordinator對象來幫助執行額外的動畫。除了present和dismiss外,當螢幕旋轉或者VC的frame更改時,也可能會觸發Transition animation。所有的Transition animation都是對View層次結構的更改。Transition Coordinator可以跟蹤同時執行額外動畫。要通路Transition Coordinator,需擷取參與轉場的VC的transitionCoordinator屬性,Transition Coordinator僅在轉場動畫執行過程中存在。

自定義動畫執行過程

當需要顯示的VC的transitionDelegate中包含一個有效對象時,UIkit會使用自定義的Animation Controller對象來顯示此VC。UIKit通過 animationController(forPresented:presenting:source:) 請求 transitioningDelegate 的一個 animation controller。如果傳回nil,轉場使用預設動畫。

Custom View Controller Transition Animation iOS自定義VC轉場動畫
  1. UIkit首先調用 Transition Animation委托的interactionControllerForPresentation方法來檢視 Interactive Animation Controller是否可用,如果傳回nil,則表明動畫不需要與使用者互動。

    UIKit調用Animation Controller對象的transitionDuration:方法來擷取轉場動畫時長。

    UIKit調用animateTransition(using:) 來執行轉場動畫。

    UIKit等待Animation Controller對象調用Transition animation對象的completeTransition:方法。自定義動畫會在動畫執行完畢後,在completion block中調用該方法來終止轉場動畫,并告知UIKit可以調用presentViewController:animated:completion:方法中的completion handler以及animator對象的animationEnded:方法。

  2. 同理,當需要移除VC時,UIKit會調用transitionDelegate的animationControllerForDismissedController:方法并執行以下步驟:

    UIKit調用轉場動畫委托的interactionControllerForDismissal:方法來檢視互動式Interactive Animation Controller對象是否可用。如果傳回nil,UIKit将不發生使用者互動。

    UIKit調用Animation Controller對象的transitionDuration:方法來擷取轉場動畫時長。

    UIKit調用animateTransition(using:) 來執行轉場動畫。

    UIKit等待Animation Controller對象調用Transition animation對象的completeTransition:方法。自定義動畫會在動畫執行完畢後,在completion block中調用該方法來終止轉場動畫,并告知UIKit可以調用presentViewController:animated:completion:方法中的completion handler以及animator對象的animationEnded:方法。

代碼實作

extension ExampleViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return ExampleDismissAnimator()
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return ExampleDismissAnimator()
    }
}

           

每當要顯示或關閉 View Controller 時,UIKit 都會請求其 transitioningDelegate 提供Animation Controller,圖中present和dismiss分别傳回兩個Animation Controller對象。

class ExampleDismissAnimator: NSObject, UIViewControllerAnimatedTransitioning {

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.25
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let fromViewController = transitionContext.viewController(forKey: .from) as? ChatTypeFilterViewController
            else {
                return
        }

        let duration = self.transitionDuration(using: transitionContext)
        UIView.animate(withDuration: duration,
                       delay: 0,
                       animations: {
                        fromViewController.colorBgView.alpha = 0
                        fromViewController.contentView.snp.remakeConstraints { (make) in
                            make.size.equalTo(fromViewController.view.bounds.size)
                            make.left.equalTo(0)
                            make.top.equalTo(fromViewController.view.snp.bottom)
                        }
                        fromViewController.view.layoutIfNeeded()
        }, completion: { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        })
    }
}
           

Animation Controller對象中使用Transition Context中的内容擷取轉場持續時間以及轉場的動畫效果,在Transition animation結束時,調用completeTransition:方法完成清理工作。因為Transition animation在執行過程中能夠被取消,是以應該使用Transition Context對象的 transitionWasCancelled 方法的傳回值來确定需要進行的清理。當顯示被取消時,Animation Controller對象必須撤銷對視圖層次結構所做的任何修改。present也需要采取類似的行動。