iOS轉場動畫封裝

寫在前面

iOS在modal 或push等操做時有默認的轉場動畫,但有時候咱們又須要特定的轉場動畫效果,從iOS7開始,蘋果就提供了自定義轉場的API,模態推送present和dismiss、導航控制器push和pop、標籤控制器的控制器切換均可以自定義轉場。動畫

自定義轉場動畫的實現步驟以下:this

一、遵循<UIViewControllerAnimatedTransitioning>協議的動畫過渡管理對象,兩個必須實現的方法:spa

    public func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval
    // This method can only  be a nop if the transition is interactive and not a percentDriven interactive transition.
    public func animateTransition(transitionContext: UIViewControllerContextTransitioning)    
    // This is a convenience and if implemented will be invoked by the system when the transition context's completeTransition: method is invoked.
    optional public func animationEnded(transitionCompleted: Bool)

二、繼承於UIPercentDrivenInteractiveTransition的手勢過渡管理對象,動畫的過程是經過百分比控制的。若是不須要手勢控制,這一步可不實現。代理

UIViewControllerInteractiveTransitioning {
    
    // This is the non-interactive duration that was returned when the
    // animators transitionDuration: method was called when the transition started.
    public var duration: CGFloat { get }
    
    // The last percentComplete value specified by updateInteractiveTransition:
    public var percentComplete: CGFloat { get }
    
    // completionSpeed defaults to 1.0 which corresponds to a completion duration of
    // (1 - percentComplete)*duration.  It must be greater than 0.0. The actual
    // completion is inversely proportional to the completionSpeed.  This can be set
    // before cancelInteractiveTransition or finishInteractiveTransition is called
    // in order to speed up or slow down the non interactive part of the
    // transition.
    public var completionSpeed: CGFloat
    
    // When the interactive part of the transition has completed, this property can
    // be set to indicate a different animation curve. It defaults to UIViewAnimationCurveEaseInOut.
    // Note that during the interactive portion of the animation the timing curve is linear. 
    public var completionCurve: UIViewAnimationCurve
    
    // These methods should be called by the gesture recognizer or some other logic
    // to drive the interaction. This style of interaction controller should only be
    // used with an animator that implements a CA style transition in the animator's
    // animateTransition: method. If this type of interaction controller is
    // specified, the animateTransition: method must ensure to call the
    // UIViewControllerTransitionParameters completeTransition: method. The other
    // interactive methods on UIViewControllerContextTransitioning should NOT be
    // called.
    
    public func updateInteractiveTransition(percentComplete: CGFloat)
    public func cancelInteractiveTransition()
    public func finishInteractiveTransition()

 

三、成爲相應的代理,實現UIViewControllerAnimatedTransitioning的代理方法,返回咱們前兩步自定義的對象。code

模態推送實現的代理方法對象

@available(iOS 2.0, *)
    optional public func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?
    
    @available(iOS 2.0, *)
    optional public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?
    
    optional public func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?
    
    optional public func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning?
    
    @available(iOS 8.0, *)
    optional public func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController?

 

轉場動畫Demo

下面直接看demo,封裝自定義的轉場動畫實現圖片在兩個控制器間放大過渡的動畫效果,面向協議進行開發,使用時將轉場動畫代理設置爲SZAnimator。blog

import UIKit
protocol SZAnimatorPresentDelegate: NSObjectProtocol {
    
    // 負責提供彈出動畫的視圖
    func presentView() -> UIView  
    func presentFrameRect() -> CGRect    
    func presentToRect() -> CGRect   
}


protocol SZAnimatorDimissDelegate: NSObjectProtocol {
 
    // 負責提供dismiss動畫的視圖
    func dismissView() -> UIView
    func dismissFrameRect() -> CGRect    
    func dismissToRect() -> CGRect   
}

class SZAnimator: NSObject {
     var isPresent: Bool = true
    weak var presentDelegate: SZAnimatorPresentDelegate?
    weak var dismissDelegate: SZAnimatorDimissDelegate?   
}


extension SZAnimator: UIViewControllerTransitioningDelegate {
    
    // 指定彈出時,處理動畫的對象
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        isPresent = true
        return self
    }
    
    // 指定彈下去時候, 處理動畫的對象
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        isPresent = false
        return self
    }    
}

// 消失動畫
// 彈出動畫
extension SZAnimator: UIViewControllerAnimatedTransitioning {
    
    // 返回動畫的時間
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return 2.0
    }
    
    // 在這裏, 實現真正的彈出, 或者消失的動畫
    // transitionContext
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {        
        isPresent ? present(transitionContext) : dismiss(transitionContext)      
    }
    
    func dismiss(transitionContext: UIViewControllerContextTransitioning) {
        
        // 自定義動畫
        // 面向協議進行開發
        // 1. 拿什麼界面作動畫
        // 2. fromRect
        // 3. toRect
        
        let animationView = dismissDelegate!.dismissView()
        transitionContext.containerView()?.addSubview(animationView)
        
        // 初始的frame
        animationView.frame = dismissDelegate!.dismissFrameRect()              
        // 最終須要展現的視圖
        if #available(iOS 8.0, *) {
            let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
        
        // 動畫
        UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
//            toView?.alpha = 1
            animationView.frame = self.dismissDelegate!.dismissToRect()
            fromView?.alpha = 0
        }) { (flag: Bool) in            
            animationView.removeFromSuperview()
            transitionContext.completeTransition(true)
        }
        }  
    }
    
    func present(transitionContext: UIViewControllerContextTransitioning) {
        // 自定義動畫
        // 面向協議進行開發
        // 1. 拿什麼界面作動畫
        // 2. fromRect
        // 3. toRect
        
        let animationView = presentDelegate!.presentView()
        transitionContext.containerView()?.addSubview(animationView)
        
        // 初始的frame
        animationView.frame = presentDelegate!.presentFrameRect()       
        
        // 最終須要展現的視圖
        if #available(iOS 8.0, *) {
            let toView = transitionContext.viewForKey(UITransitionContextToViewKey)
        
        toView?.frame = UIScreen.mainScreen().bounds
        transitionContext.containerView()?.addSubview(toView!)
        toView?.alpha = 0
        
        // 動畫
        UIView.animateWithDuration(2.0, animations: {
            toView?.alpha = 1
            animationView.frame = self.presentDelegate!.presentToRect()     
        }) { (flag: Bool) in
            
            animationView.removeFromSuperview()
            transitionContext.completeTransition(true)
        }
        }       
    }
}
相關文章
相關標籤/搜索