iOS動畫:ViewController過渡動畫之UINavigationController轉場動畫(12)

和前一章類似,僅僅是代理方法的不同。
主要用到UINavigationControllerDelegate的代理方法navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController),該代理方法也是需要返回一個UIViewControllerAnimatedTransitioning的可選對象,當返回nil時,UIKit將使用內置系統默認動畫,當不爲nil時,將使用你自己自定義的動畫效果。

現在有這樣一個場景
image_1
我們來創建一個動畫構造器

class RevealAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    let animationDuration = 2.0
    var operation: UINavigationControllerOperation = .push
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return animationDuration
    }
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        
    }
}

然後在MasterViewController.swift的viewDidLoad中配置代理

	navigationController?.delegate = self

實現代理方法

extension MasterViewController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        transition.operation = operation
        return transition
    }
}

現在我們來實現動畫構造器RevealAnimator中的方法。
因爲需要創建一些layer動畫,我們先存一下動畫上下文。

	weak var storedContext: UIViewControllerContextTransitioning?

然後在animateTransition()中添加初始化轉場代碼

	storedContext = transitionContext
    if operation == .push {
	    let fromVC = transitionContext.viewController(forKey: .from) as! MasterViewController
        let toVC = transitionContext.viewController(forKey: .to) as! DetailViewController
        
        transitionContext.containerView.addSubview(toVC.view)//將toView添加到容器當中
        toVC.view.frame = transitionContext.finalFrame(for: toVC)//設置toView的座標
        ...
    }

現在我們添加一個放大logo切換場景的動畫

	        let animation = CABasicAnimation(keyPath: "transform")
        animation.fromValue = NSValue(caTransform3D: CATransform3DIdentity)
        animation.toValue = NSValue(caTransform3D: CATransform3DConcat(CATransform3DMakeTranslation(0.0, -10.0, 0.0), CATransform3DMakeScale(150.0, 150.0, 1.0)))
        animation.duration = animationDuration
        animation.delegate = self
        animation.fillMode = kCAFillModeForwards
        animation.isRemovedOnCompletion = false
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
        
        let maskLayer: CAShapeLayer = RWLogoLayer.logoLayer()
        maskLayer.position = fromVC.logo.position
        toVC.view.layer.mask = maskLayer
        maskLayer.add(animation, forKey: nil)
        fromVC.logo.add(animation, forKey: nil)

運行效果
image_2
爲了移除fromVC的logo,同樣也添加一個動畫

	fromVC.logo.add(animation, forKey: nil)

動畫結束時,我們需要設置轉場動畫完成,並移除fromVC的所有動畫,再將toVC的mask清空

    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if let context = storedContext {
            context.completeTransition(!context.transitionWasCancelled)
            let fromVC = context.viewController(forKey: .from) as! MasterViewController
            fromVC.logo.removeAllAnimations()
            let toVC = context.viewController(forKey: .to) as! DetailViewController
            toVC.view.layer.mask = nil
        }
        storedContext = nil
    }

實現效果:
image_2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章