1. 程式人生 > >Swift基礎之自定義PUSH和POP跳轉動畫

Swift基礎之自定義PUSH和POP跳轉動畫

之前用OC程式碼寫過PUSH和POP的轉場動畫,閒來無事,將其轉換成Swift語言,希望對大家有幫助,轉載請註明。。。。

如何實現PUSH和POP的轉場動畫?

首先,建立一個NSObject的類,分別用來實現PUSH和POP的動畫效果

建立PUSH檔案,實現扇形效果,程式碼如下:

需要注意的是,代理的實現方法要完整

var transitionContextT:UIViewControllerContextTransitioning?
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.8
    }
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        
        self.transitionContextT = transitionContext
        
        let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        //不新增的話,螢幕什麼都沒有
        let containerView = transitionContext.containerView
        containerView.addSubview((fromVC?.view)!)
        containerView.addSubview((toVC?.view)!)
        
        let originRect:CGRect = CGRect.init(x: 0, y: 0, width: 50, height: 50)
        let maskStartPath = UIBezierPath.init(ovalIn: originRect)
        //OC中CGRectInset(originRect, -2000, -2000)的Swift用法:originRect.insetBy(dx: -2000, dy: -2000)
        let maskEndPath = UIBezierPath.init(ovalIn: originRect.insetBy(dx: -2000, dy: -2000))
        
        //建立一個CAShapeLayer來負責展示圓形遮蓋
        let maskLayer = CAShapeLayer.init()
        //將他的path指定為最終的path,來避免在動畫完成後回彈
        maskLayer.path = maskEndPath.cgPath
        
        toVC?.view.layer.mask = maskLayer
        
        let maskAnimation = CABasicAnimation.init(keyPath: "path")
        maskAnimation.fromValue = maskStartPath.cgPath
        maskAnimation.toValue = maskEndPath.cgPath
        maskAnimation.duration = self.transitionDuration(using: transitionContext)
        maskAnimation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
        maskAnimation.fillMode = kCAFillModeForwards
        maskAnimation.isRemovedOnCompletion = false
        maskAnimation.delegate = self
        maskLayer.add(maskAnimation, forKey: "path")
        
    }
    //MARK:----- CAAnimationDelegate
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        self.transitionContextT?.completeTransition(!(self.transitionContextT?.transitionWasCancelled)!)
        //去除mask
        self.transitionContextT?.viewController(forKey: UITransitionContextViewControllerKey.from)?.view.layer.mask = nil;
        self.transitionContextT?.viewController(forKey: UITransitionContextViewControllerKey.to)?.view.layer.mask = nil;
    }

然後,同理建立POP檔案,實現彈跳的效果,程式碼如下:

var transitionContext:UIViewControllerContextTransitioning?
    
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.8
    }
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        
        self.transitionContext = transitionContext
        
        let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        //不新增的話,螢幕什麼都沒有
        let containerView = transitionContext.containerView
        containerView.addSubview((fromVC?.view)!)
        containerView.addSubview((toVC?.view)!)
        
        let durationN = self.transitionDuration(using: transitionContext)
        let screenBounds:CGRect = UIScreen.main.bounds
        let finalFrame:CGRect = transitionContext.finalFrame(for: toVC!)
        //OC中CGRectOffset(finalFrame, 0, -screenBounds.size.height)的Swift的用法:finalFrame.offsetBy(dx: 0, dy: -screenBounds.size.height)
        toVC?.view.frame = finalFrame.offsetBy(dx: 0, dy: -screenBounds.size.height)

        //新增動畫,有彈跳的效果,引數:usingSpringWithDamping的範圍為0.0f到1.0f,數值越小「彈簧」的振動效果越明顯,當設定為1.0時,就不彈跳
        //toVC?.view.frame = finalFrame
        //transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        UIView.animate(withDuration: durationN, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.0, options: UIViewAnimationOptions.curveLinear, animations: {() -> Void in
            //print("11111111")
            toVC?.view.frame = finalFrame
        }, completion: ({(Bool) -> Void in
            //print("22222222")
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }))
    }

最後在需要使用跳轉動畫的地方新增self.navigationController?.delegate = self代理方法,並實現,程式碼如下:

//MARK:-----UINavigationControllerDelegate
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation==UINavigationControllerOperation.push {
            return BHPopAnimation()
        }
        else if operation==UINavigationControllerOperation.pop{
            return BHPushAnimation()
        }
        return nil
    }