iOS 自定義轉場動畫

在開發中,不管咱們使用 Push 仍是 Present 推出新的 ViewController 時,系統爲了提升用戶體驗都會爲咱們默認加上一些過渡動畫。可是,系統默認的動畫老是不能知足你們各類各樣的需求的,因此係統也爲咱們提供了在不一樣場景下自定義過渡動畫以及經過手勢控制過渡進度的實現方案。git

這篇文章記錄了自定義轉場動畫中的幾種狀況:程序員

  • 模態跳轉(Present)
  • 導航控制器跳轉(Push)
  • UITabbarController
  • 三方框架——Lottie

效果圖

預備

首先,咱們如今介紹幾個在自定義轉場動畫時須要接觸的協議:github

  • UIViewControllerAnimatedTransitioning: 實現此協議的實例控制轉場動畫效果。json

  • UIViewControllerInteractiveTransitioning: 實現此協議的實例控制着利用手勢過渡時的進度處理。bash

咱們在定義好了實現上面兩個協議的類後,只須要在須要進行轉場的地方,提供對應的對象便可。app

ps:下面的實例中,請你們忽略動畫效果,關注實現。(實際上是懶得去寫太多動畫了。🤦‍♂️)框架

模態跳轉(Present)

場景

self.present(vc!, animated: true) {} 
self.dismiss(animated: true) {} 
複製代碼

實現步驟

  1. 設置將要 present 的 ViewController 的 transitioningDelegate 對象,此對象是實現協議 UIViewControllerTransitioningDelegate 的實例。
  2. 實現 UIViewControllerTransitioningDelegate 協議中的幾個代理方法,返回實現了 UIViewControllerAnimatedTransitioning 協議的動畫效果控制類。

須要實現的UIViewControllerTransitioningDelegate方法:ide

//返回用於 present 的自定義 transition 動畫
optional func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning?
    
//返回用於 dismiss 的自定義 transition 動畫
optional func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
複製代碼

實例

/// 第一個 VC 中點擊跳轉
func presentClick(_ sender: Any) {
        let vc = self.storyboard?.instantiateViewController(withIdentifier: "PresentSecondViewController")
        
        vc?.modalPresentationStyle = .fullScreen
        
        vc?.transitioningDelegate = self
        
        self.present(vc!, animated: true) {}
}

// 第一個 VC 實現協議,返回控制轉場動畫效果的實例
extension PresentFirstViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return NormalPresentAnimator()
    }
    
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return NormalPresentAnimator()
    }
}
複製代碼

導航控制器跳轉(Push)

場景

self.navigationController?.pushViewController(vc!, animated: true)
self.navigationController?.popViewController(animated: true)
複製代碼

實現步驟

  1. 設置導航控制器 UINavigationController 的 delegate。
  2. 實現 UINavigationControllerDelegate 協議中的代理方法,返回實現了 UIViewControllerAnimatedTransitioning 協議的動畫效果控制類。

須要實現的UINavigationControllerDelegate方法:動畫

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

實例

class PushFirstViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.navigationController?.delegate = self
    }

    @IBAction func pushClick(_ sender: Any) {
        let vc = self.storyboard?.instantiateViewController(withIdentifier: "PushSecondViewController")
        
        self.navigationController?.pushViewController(vc!, animated: true)
    }
}
extension PushFirstViewController: UINavigationControllerDelegate {
    //返回自定義過渡動畫
    func navigationController(_ navigationController: UINavigationController,
                              animationControllerFor operation: UINavigationController.Operation,
                              from fromVC: UIViewController,
                              to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation == .pop && fromVC is PushFirstViewController {
            return nil
        }
        
        return NormalPushAnimator()
    }
}
複製代碼

UITabbarController

在前面的兩個專場實現中,咱們在須要轉場的類中分別實現了UIViewControllerTransitioningDelegateUINavigationControllerDelegate 方法,在這兩個協議中,還有這樣幾個方法:ui

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

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

/// UINavigationControllerDelegate
optional func navigationController(_ navigationController: UINavigationController,
                                       interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?
複製代碼

上面這幾個方法呢?其實就是咱們經過利用手勢轉場時過渡的進度處理方法。咱們須要在代理方法中返回一個實現了 UIViewControllerInteractiveTransitioning 協議的對象來對轉場進度進行控制。下面的 UITabbarController 中我就實現一個利用手勢控制轉場的例子。 Present 及 Push/Pop 按照相同的思路實現便可。

場景

UITabbarController 在默認的狀態下,切換控制器時是沒有動畫效果的。若是須要動畫效果的話,須要咱們進行自定義。

實現步驟

  1. 設置 UITabbarController 的 delegate。
  2. 實現 UITabBarControllerDelegate 協議中的代理方法,返回實現了 UIViewControllerAnimatedTransitioning 協議的動畫效果控制類,以及返回實現了 UIViewControllerInteractiveTransitioning 協議的轉場進度控制類。
/// 返回實現了 UIViewControllerAnimatedTransitioning 協議的實例
func tabBarController(_ tabBarController: UITabBarController,
                          animationControllerForTransitionFrom fromVC: UIViewController,
                          to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?

/// 返回實現了 UIViewControllerInteractiveTransitioning 協議的實例       
func tabBarController(_ tabBarController: UITabBarController,
                          interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?
複製代碼

實例

class TabbarController: UITabBarController, UITabBarControllerDelegate {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.delegate = self
}

func tabBarController(_ tabBarController: UITabBarController,
                          animationControllerForTransitionFrom fromVC: UIViewController,
                          to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
    if self.selectedIndex == 0 {
        return TabbarAnimator(edge: .right)
    } else {
        return TabbarAnimator(edge: .left)
    }
}
    
func tabBarController(_ tabBarController: UITabBarController,
                          interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
    if self.panGesture.state == .began || self.panGesture.state == .changed {
        return TabbarInteractionTransition(pan: self.panGesture)
    } else {
        return nil
    }
}

複製代碼

三方框架——Lottie

介紹

Lottie 是 Android 和 iOS 的移動庫,用 bodymovin 解析 Adobe After Effects 導出爲 json 的動畫並在移動設備上生成矢量動畫。設計師能夠輕鬆的建立漂亮(複雜)的動畫,無需程序員辛苦地手動去建立及調試。

場景

實現一些特殊的轉場,且程序員無足夠時間調試動畫時。

實現步驟

  1. 在工程中導入 Lottie 框架。
  2. 在須要轉場的類中,將 Lottie import。
  3. 由於 Lottie 實現的轉場其實是 Present 的轉場,因此設置將要 Present 的控制器的 transitioningDelegate。
  4. 實現 UIViewControllerTransitioningDelegate 協議中的幾個代理方法,返回利用轉場動畫 json 文件初始化的 LOTAnimationTransitionController 的實例。

ps:Lottie 轉場的 LOTAnimationTransitionController 在 3.0.0 版本後被移除,因此須要使用 Lottie 作轉場時,須要在導入時,指定版本號爲更早的版本。我這裏使用的是 2.5.3。

實例

/// 第一個 VC
func presentClick(_ sender: Any) {
    let vc = self.storyboard?.instantiateViewController(withIdentifier: "LottieSecondViewController")
    
    vc?.transitioningDelegate = self
    
    self.present(vc!, animated: true) {}
}

/// 實現 UIViewControllerTransitioningDelegate,返回  LOTAnimationTransitionController 的實例
extension LottieFirstViewController: UIViewControllerTransitioningDelegate {
    func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        let transitionController = LOTAnimationTransitionController(animationNamed: "Count",
                                                                    fromLayerNamed: "",
                                                                    toLayerNamed: "",
                                                                    applyAnimationTransform: false)
        return transitionController
    }
    
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        let transitionController = LOTAnimationTransitionController(animationNamed: "Three",
                                                                    fromLayerNamed: "",
                                                                    toLayerNamed: "",
                                                                    applyAnimationTransform: false)
        return transitionController
    }
}

複製代碼

總結

上面的全部動畫的示例能夠在個人Github上找到哦,各位前快去下載把玩吧。

好的轉場動畫,在用戶交互上會帶來更加美妙的體驗。讓用戶盡享絲滑哦。

相關文章
相關標籤/搜索