美文网首页swiftSwift学习特效动画
swift 深入解析push 和 present自定义转场动画

swift 深入解析push 和 present自定义转场动画

作者: 小曼blog | 来源:发表于2018-10-27 19:10 被阅读142次

    学习一下push和present的自定义转场动画。
    demo地址:https://github.com/weiman152/TransitionDemo
    从iOS7开始,苹果更新了自定义ViewController转场的API。

    几个protocol:
    讲自定义转场就离不开这几个protocol:

    UIViewControllerContextTransitioning
    UIViewControllerAnimatedTransitioning
    UIViewControllerInteractiveTransitioning
    UIViewControllerTransitioningDelegate
    UINavigationControllerDelegate
    UITabBarControllerDelegate

    我们这个demo中就使用了
    UIViewControllerContextTransitioning,
    UIViewControllerAnimatedTransitioning,
    UIViewControllerTransitioningDelegate,
    UINavigationControllerDelegate。

    实现效果:
    push:


    QQ20181026-211948.gif

    present:

    QQ20181027-183358.gif 3333.gif

    源码:

    PushTransition

    //
    //  PushTransition.swift
    //  TransitionDemo
    //
    //  Created by iOS on 2018/10/26.
    //  Copyright © 2018年 weiman. All rights reserved.
    //
    
    import UIKit
    
    class PushTransition: NSObject {
        
        enum `Type` {
            case scale
            case formTop
            case fromBottom
        }
        
        private let ScreenWidth = UIScreen.main.bounds.size.width
        private let ScreenHeight = UIScreen.main.bounds.size.height
        
        static private var duration = 0.5
        static private var type: Type = .scale
        // 设置转场代理
        static var transition = PushTransition()
        
        /// 带动画的push
        ///
        /// - Parameters:
        ///   - fromVC: 发起push操作的VC
        ///   - toVC: 即将被push出来的VC
        ///   - type: 需要哪种动画
        ///   - duration: 动画执行的时间
        static func pushWithTransition(fromVC: UIViewController,
                                       toVC: UIViewController,
                                       type: Type = .scale,
                                       duration: Double = 0.5) {
            self.type = type
            self.duration = duration
            fromVC.navigationController?.delegate = PushTransition.transition
            fromVC.navigationController?.pushViewController(toVC, animated: true)
            fromVC.navigationController?.delegate = nil
        }
    
    }
    
    extension PushTransition: UIViewControllerAnimatedTransitioning {
        
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            
            return PushTransition.duration
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            
            let toVC = transitionContext.viewController(forKey: .to)
            let fromVC = transitionContext.viewController(forKey: .from)
            
            guard let fromView = fromVC?.view,
                let toView = toVC?.view else {
                    return
            }
            
            switch PushTransition.type {
            case .scale:
                scale(fromView: fromView,
                      toView: toView,
                      transitionContext: transitionContext)
            case .formTop:
                fromTop(fromView: fromView,
                        toView: toView,
                        transitionContext: transitionContext)
            case .fromBottom:
                fromBottom(fromView: fromView,
                           toView: toView,
                           transitionContext: transitionContext)
            }
        }
    }
    
    extension PushTransition: UINavigationControllerDelegate {
        
        func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            
            return PushTransition()
        }
    }
    
    extension PushTransition {
    
        /// 缩放的push
        ///
        /// - Parameters:
        ///   - fromView: 发起push操作的VC的View
        ///   - toView: 即将被push出来的VC的view
        ///   - transitionContext: 上下文
        private func scale(fromView: UIView,
                           toView: UIView,
                           transitionContext: UIViewControllerContextTransitioning)
        {
            transitionContext.containerView.addSubview(toView)
            transitionContext.containerView.bringSubviewToFront(fromView)
            
            UIView.animate(withDuration: PushTransition.duration, animations: {
                
                fromView.alpha = 0
                fromView.transform = CGAffineTransform(scaleX: 0.2, y: 0.2)
                toView.alpha = 1.0
                
            }) { (_) in
                
                fromView.transform = CGAffineTransform(scaleX: 1, y: 1)
                transitionContext.completeTransition(true)
                fromView.alpha = 1.0
            }
        }
        
        /// 从上到下的push
        ///
        /// - Parameters:
        ///   - fromView: 发起push操作的VC的View
        ///   - toView: 即将被push出来的VC的view
        ///   - transitionContext: 上下文
        private func fromTop(fromView: UIView,
                             toView: UIView,
                             transitionContext: UIViewControllerContextTransitioning)
        {
            transitionContext.containerView.addSubview(toView)
            
            toView.transform = CGAffineTransform(translationX: 0,
                                                 y: -self.ScreenHeight)
            UIView.animate(withDuration: PushTransition.duration, animations: {
                toView.transform = CGAffineTransform(translationX: 0, y: 0)
                toView.alpha = 1.0
                
            }) { (_) in
                transitionContext.completeTransition(true)
            }
        }
        
        /// 从下往上的push
        ///
        /// - Parameters:
        ///   - fromView: 发起push操作的VC的View
        ///   - toView: 即将被push出来的VC的view
        ///   - transitionContext: 上下文
        private func fromBottom(fromView: UIView,
                                toView: UIView,
                                transitionContext:  UIViewControllerContextTransitioning)
        {
            transitionContext.containerView.addSubview(toView)
            
            toView.transform = CGAffineTransform(translationX: 0,
                                                 y: self.ScreenHeight)
            UIView.animate(withDuration: PushTransition.duration, animations: {
                toView.transform = CGAffineTransform(translationX: 0, y: 0)
                toView.alpha = 1.0
                
            }) { (_) in
                transitionContext.completeTransition(true)
            }
            
        }
    }
    
    

    PresentTransition:

    //
    //  PresentTransition.swift
    //  TransitionDemo
    //
    //  Created by iOS on 2018/10/26.
    //  Copyright © 2018年 weiman. All rights reserved.
    //
    
    import UIKit
    
    class PresentTransition: NSObject {
        
        enum Animate {
            case scale
            case fromLeft
            case fromRight
        }
        
        enum Transition {
            case present
            case dismiss
        }
        
        private let ScreenWidth = UIScreen.main.bounds.size.width
        private let ScreenHeight = UIScreen.main.bounds.size.height
        // 设置转场代理
        static private let transition = PresentTransition()
        
        static private var duration = 1.0
        static private var type: Animate = .scale
        static private var tran: Transition = .present
        
        static func presentWithAnimate(fromVC: UIViewController,
                                toVC: UIViewController,
                                duration: Double = 1.0,
                                animate: Animate = .scale) {
            PresentTransition.duration = duration
            PresentTransition.type = animate
            
            toVC.transitioningDelegate = PresentTransition.transition
            fromVC.present(toVC, animated: true) { }
        }
    
    }
    
    extension PresentTransition: UIViewControllerAnimatedTransitioning {
        
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return PresentTransition.duration
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            
            switch PresentTransition.tran {
            case .present:
                presentTransition(transitionContext: transitionContext)
            case .dismiss:
                dismissTransition(transitionContext: transitionContext)
            }
        }
    }
    
    extension PresentTransition: UIViewControllerTransitioningDelegate {
        
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            
            PresentTransition.tran = .present
            return PresentTransition()
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            
            PresentTransition.tran = .dismiss
            return PresentTransition()
        }
    }
    
    extension PresentTransition {
        
        private func presentTransition(transitionContext: UIViewControllerContextTransitioning) {
            
            let toVC = transitionContext.viewController(forKey: .to)
            let fromVC = transitionContext.viewController(forKey: .from)
            
            guard let fromView = fromVC?.view,
                let toView = toVC?.view else {
                    return
            }
            
            transitionContext.containerView.addSubview(toView)
            
            switch PresentTransition.type {
            case .scale:
                scalePresent(fromView: fromView,
                             toView: toView,
                             transitionContext: transitionContext)
            case .fromLeft:
                fromLeftPresent(fromView: fromView,
                                toView: toView,
                                transitionContext: transitionContext)
            case .fromRight:
                fromRightPresent(fromView: fromView,
                                 toView: toView,
                                 transitionContext: transitionContext)
            }
            
        }
        
        private func dismissTransition(transitionContext: UIViewControllerContextTransitioning) {
            
            let toVC = transitionContext.viewController(forKey: .to)
            let fromVC = transitionContext.viewController(forKey: .from)
            
            guard let fromView = fromVC?.view,
                let toView = toVC?.view else {
                    return
            }
            
            switch PresentTransition.type {
            case .scale:
                scaleDismiss(fromView: fromView,
                             toView: toView,
                             transitionContext: transitionContext)
            case .fromLeft:
                fromLeftDismiss(fromView: fromView,
                                toView: toView,
                                transitionContext: transitionContext)
            case .fromRight:
                fromRightDismiss(fromView: fromView,
                                 toView: toView,
                                 transitionContext: transitionContext)
            }
        }
        
        private func scalePresent(fromView: UIView,
                                  toView: UIView,
                                  transitionContext: UIViewControllerContextTransitioning)
        {
            toView.alpha = 0.0
            toView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
            UIView.animate(withDuration: PresentTransition.duration, animations: {
                toView.alpha = 1.0
                toView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
            }) { (_) in
                toView.alpha = 1.0
                toView.transform = CGAffineTransform(scaleX: 1.0, y: 1.0)
                transitionContext.completeTransition(true)
            }
        }
        
        private func scaleDismiss(fromView: UIView,
                                  toView: UIView,
                                  transitionContext: UIViewControllerContextTransitioning)
        {
            transitionContext.containerView.insertSubview(toView, belowSubview: fromView)
            UIView.animate(withDuration: PresentTransition.duration, animations: {
                fromView.transform = CGAffineTransform(scaleX: 0.01, y: 0.01)
            }) { (_) in
                transitionContext.completeTransition(true)
            }
        }
        
        private func fromLeftPresent(fromView: UIView,
                                     toView: UIView,
                                     transitionContext: UIViewControllerContextTransitioning)
        {
            toView.frame = CGRect(x: -ScreenWidth, y: 0, width: ScreenWidth, height: ScreenHeight)
            UIView.animate(withDuration: PresentTransition.duration, animations: {
                toView.frame = CGRect(x: 0, y: 0, width: self.ScreenWidth, height: self.ScreenHeight)
                toView.layoutSubviews()
            }) { (_) in
                transitionContext.completeTransition(true)
            }
            
        }
        
        private func fromLeftDismiss(fromView: UIView,
                                     toView: UIView,
                                     transitionContext: UIViewControllerContextTransitioning)
        {
            transitionContext.containerView.insertSubview(toView, belowSubview: fromView)
            UIView.animate(withDuration: PresentTransition.duration, animations: {
                fromView.transform = CGAffineTransform(translationX: 0, y: self.ScreenHeight)
                fromView.alpha = 0
            }) { (_) in
                transitionContext.completeTransition(true)
            }
        }
        
        private func fromRightPresent(fromView: UIView,
                                      toView: UIView,
                                      transitionContext: UIViewControllerContextTransitioning)
        {
            toView.frame = CGRect(x: ScreenWidth, y: 0, width: ScreenWidth, height: ScreenHeight)
            UIView.animate(withDuration: PresentTransition.duration, animations: {
                toView.frame = CGRect(x: 0, y: 0, width: self.ScreenWidth, height: self.ScreenHeight)
                toView.layoutSubviews()
            }) { (_) in
                transitionContext.completeTransition(true)
            }
        }
        
        private func fromRightDismiss(fromView: UIView,
                                      toView: UIView,
                                      transitionContext: UIViewControllerContextTransitioning)
        {
            transitionContext.containerView.insertSubview(toView, belowSubview: fromView)
            UIView.animate(withDuration: PresentTransition.duration, animations: {
                fromView.transform = CGAffineTransform(translationX: 0, y: self.ScreenHeight)
                fromView.alpha = 0
            }) { (_) in
                transitionContext.completeTransition(true)
            }
        }
    }
    
    

    参考文章:
    https://www.jianshu.com/p/e7155f938e59

    相关文章

      网友评论

        本文标题:swift 深入解析push 和 present自定义转场动画

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