美文网首页
基于Swift3.0下的转场动画

基于Swift3.0下的转场动画

作者: 哎呀不错 | 来源:发表于2016-09-20 09:25 被阅读0次

    我们知道,当一个控制器要弹出另一个控制器时,主要分为两大类,第一种是带导航栏的,push/show等等。这里不作解释,本文章主要针对modal方式自定义转场动画,效果如下:


    transitionAnimation.gif

    实现这样的效果其实并不复杂,但是有很多细节需要注意。
    首先,当我们不自定义转成动画的时候一般都说是像下面这么写就够了。

    self.present(crossDissolveSecondVC, animated: true, completion: nil)
    

    从上面的代码中我们似乎找不到自定义动画的接口,那么这里就需要了解一个关键了---转场动画代理 UIViewControllerTransitioningDelegate
    如下:

    // 设置被modal出来的控制器的样式,此处不写这句代码也可。
     crossDissolveSecondVC.modalPresentationStyle = .fullScreen
    // crossDissolveSecondVC表示被modal出来的控制器。
     crossDissolveSecondVC.transitioningDelegate = self
    

    设置完这句以后,我们遵循协议,进入看一下这个协议中的关键方法:

        // present动画
        @objc(animationControllerForPresentedController:presentingController:sourceController:) func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return DHPresentAnimator()
        }
        // dismiss动画
        @objc(animationControllerForDismissedController:) func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {  
    //        return DHPresentAnimator()
            return DHDismissAnimator()
        }
    
    

    我们可以发现上述两个代理方法,一个是针对present的代理方法,
    一个是针对dismiss的时候的代理方法。这两个方法的共同点是都需要返回一个遵守UIViewControllerAnimatedTransitioning协议的对象。
    那么下一步我们来创建这样一个遵守协议的类。
    如下:

    class DHPresentAnimator: NSObject, UIViewControllerAnimatedTransitioning, CAAnimationDelegate {
    }
    

    当你写到这里的时候会报错,因为遵守UIViewControllerAnimatedTransitioning协议的类必须实现两个代理方法,这里只需要按照提示实现即可。具体我们看这两个方法各有什么作用。

    // MARK: - CAAnimationDelegate的代理方法
    extension DHPresentAnimator {
        
        // 这个代理方法设置动画的执行时间
        @objc(transitionDuration:) public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            
            return transitionDuration
        }
        // 这个方法里面主要实现动画细节
        @objc(animateTransition:) public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            
            // 记录transitionContext
            transitionCtx = transitionContext
            
            // 这里指的是firstVC
    //        let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
            
            // 这里指的是secondVC
            toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
            
            let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)
            
            toView = transitionContext.view(forKey: UITransitionContextViewKey.to)
            
            let containerView = transitionContext.containerView
            
            print(fromView.self)
            print(toView.self)
            print(containerView.self)
            // 这一步是必须的,当prsent动画时需要将modal出来的视图加到containerView中去,
            containerView.addSubview(toView!)
            
            // 加入旋转动画。
            toView?.layer.add(rotateAnimation, forKey: "rotate")
            
        }
    
    }
    

    以上代码我创建的是一个旋转的动画(CAAnimation),如下:

        // 动画的执行时间
        let transitionDuration = 2.0
        
        // 旋转动画
        lazy var rotateAnimation: CABasicAnimation = {
            let animation = CABasicAnimation(keyPath: "transform.rotation")
            animation.fromValue = 0.0
            animation.toValue = M_PI * 2
            animation.duration = self.transitionDuration
            animation.delegate = self
    
            return animation
        }()
        
    

    这里最关键的一部就是,当动画执行完毕以后我们需要执行以下代码:

    // 这段代码的意思相当于动画的结束标志。
     transitionCtx?.completeTransition(!(transitionCtx?.transitionWasCancelled)!)
    

    那么问题来了?我们怎么知道动画什么时候执行完毕,这个时候还是得找代理CAAnimationDelegate,刚刚我们在懒加载中定义动画的一些旋转参数时就已经设置了代理,然后遵循CAAnimationDelegate这个代理协议。我们不难找到:

    // MARK: - CAAnimationDelegate 的代理方法
    extension DHPresentAnimator {
        
        public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
            print("animationEnd")
           
            // 动画结束以后会调该方法
            if flag == true { // 代表正常结束
                transitionCtx?.completeTransition(!(transitionCtx?.transitionWasCancelled)!)
                print(toView?.frame)
                
                // 移除这个动画
                toView?.layer.removeAnimation(forKey: "rotate")
    //            toView?.alpha = 1.0
            }
        
        }
        func animationDidStart(_ anim: CAAnimation) {
            print("animationBegin")
        }
    }
    

    说到这里转场动画的基本套路就说完了,其实是怎么一回事呢?要想自定义转场动画,无非就是遵循协议,实现代理方法,在代理方法中拿到即将要出现的视图,拿到这个视图以后我们做相关操作,比如旋转,平移,等等都可以。这就是转场动画的核心部分。
    相关代码链接如下:
    https://github.com/iLMagic/-.git

    相关文章

      网友评论

          本文标题:基于Swift3.0下的转场动画

          本文链接:https://www.haomeiwen.com/subject/gynnettx.html