zoukankan      html  css  js  c++  java
  • 自定义Controller转场动画

    当你想使用一个自定义的模态表示类型来呈现一个视图控制器时,设置它的modalPresentationStyle属性为custom,并将一个符合这个协议的对象分配给它的transitioningDelegate属性。当你展示那个视图控制器时,UIKit查询你的转换代理当视图控制器进入位置时使用的对象。

    //一 创建控制器
    class TransitionViewController: UIViewController {
    
        var endVelocity: CGPoint?
        let imageView = UIImageView(frame: CGRect(x: 25, y: 25,  150, height: 150))
        init() {
            super.init(nibName: nil, bundle: nil)
            self.modalPresentationStyle = .custom
            self.transitioningDelegate = self
            
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .orange
    
            imageView.image = UIImage(named: "666")
            view.addSubview(imageView)
            imageView.isUserInteractionEnabled = true
            let tap1 = UITapGestureRecognizer(target: self, action: #selector(clickImage))
            imageView.addGestureRecognizer(tap1)
            
            let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
            view.addGestureRecognizer(pan)
            
        }
       
        @objc func clickImage(){
            self.dismiss(animated: true, completion: nil)
        }
        
        @objc func handlePan(gesture: UIPanGestureRecognizer) {
               if gesture.state == .began {
                   
               } else if gesture.state == .changed {
                  let translation = gesture.translation(in: view.superview)
                  let center = view.center
                   UIView.animate(withDuration: 0.1) {
                       self.view.center = .init(x: center.x + translation.x, y: center.y + translation.y)
                       gesture.setTranslation(.zero, in: self.view.superview)
                   }
                   
               } else {
                let screenCenter = CGPoint(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height/2)
                   let viewCenter = view.center
                   
                   let dis = sqrt(pow((screenCenter.x - viewCenter.x), 2) + pow((screenCenter.y - viewCenter.y), 2))
                   let vl = gesture.velocity(in: view.superview)
                   let v = sqrt(pow(vl.x,2)+pow(vl.y, 2))
                   if dis >= 120 || v > 500 {
                       if v > 500 {
                           endVelocity = gesture.velocity(in: view.superview)
                       }
                       dismiss(animated: true, completion: nil)
                   } else {
                       UIView.animate(withDuration: 0.3) {
                           self.view.center = screenCenter
                       }
                   }
               }
           }
       
    }

    ///第二步 实现代理协议

    extension TransitionViewController : UIViewControllerTransitioningDelegate{
        
        //模态进入时的动画
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return  DqPresentAnimation()
        }
       //模态推出时的动画
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return DqDismissAnimation()
        }
        //从模态开始到推出的一个控制器,比推出的控制器生命周期更长
        
        /// - Parameters:
        ///   - presented: 已推出的控制器
        ///   - presenting: 正在推出的控制器
        ///   - source: 原始控制器
        /// - Returns: 返回自己创建的过程控制器
        func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
            return DqPresentationController(presentedViewController: presented, presenting: presenting)
        }
        
    }

    /// 第三步 实现Present和Dismiss动画协议

    class DqPresentAnimation: NSObject,UIViewControllerAnimatedTransitioning {
        
        //动画时间
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.6
        }
        //具体动画
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            
            let toViewController = transitionContext.viewController(forKey: .to)
            let containerView = transitionContext.containerView
    
            let toView = toViewController!.view!
            
            let finalFrame = transitionContext.finalFrame(for: toViewController!)
            toView.frame = finalFrame
    
            containerView.addSubview(toView)
            
            toView.center = .init(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height/2 + 50)
            toView.alpha = 0
            toView.layer.masksToBounds = true
            toView.layer.cornerRadius = 20
            toView.layer.masksToBounds = false
    
            toView.isUserInteractionEnabled = true
            toView.layer.shadowRadius = 20
            let path = UIBezierPath(roundedRect: toView.bounds.insetBy(dx: 20, dy: 20), cornerRadius: 20)
            toView.layer.shadowPath = path.cgPath
            toView.layer.shadowOffset = .init( 0, height: 25)
            toView.layer.shadowOpacity = 0.6
    
            let animator = UIDynamicAnimator()
                animator.removeAllBehaviors()
            let snapBehavior = UISnapBehavior(item: toViewController!.view, snapTo: .init(x: UIScreen.main.bounds.width/2, y: UIScreen.main.bounds.height/2))
            snapBehavior.damping = 0.1
            animator.addBehavior(snapBehavior)
            
            UIView.animate(withDuration: 0.6, animations: {
                toView.alpha = 1
            }) { (finish) in
                animator.removeAllBehaviors()
                transitionContext.completeTransition(true)
            }
        }
        
    }
    
    //Dismiss动画
    class DqDismissAnimation: NSObject,UIViewControllerAnimatedTransitioning {
        
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.6
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            let fromViewController = transitionContext.viewController(forKey: .from) as! TransitionViewController
            let toViewController = transitionContext.viewController(forKey: .to)
            let containerView = transitionContext.containerView
            
            let fromView = fromViewController.view!
            let toView = toViewController!.view!
            //系统会给view改为不可交互,需要手动打开交互
            toView.isUserInteractionEnabled = true
            
            containerView.addSubview(fromView)
            
            if let velocity = fromViewController.endVelocity {
                    
                    let magnitude = sqrt((velocity.x * velocity.x) + (velocity.y * velocity.y))
                    let slideMultiplier = magnitude / 100
                    print("magnitude: (magnitude), slideMultiplier: (slideMultiplier)")
                      
                    // 2
                    let slideFactor = 1 * slideMultiplier     //Increase for more of a slide
                    // 3
                    var finalPoint = CGPoint(x:fromView.center.x + (velocity.x * slideFactor),
                                               y:fromView.center.y + (velocity.y * slideFactor))
                    // 4
                finalPoint.x = min(max(finalPoint.x, 0), UIScreen.main.bounds.width + 150)
                    finalPoint.y = min(max(finalPoint.y, 0), UIScreen.main.bounds.height + 150)
                      
                    // 5
                    UIView.animate(withDuration: 0.2, animations: {
                        fromView.center = finalPoint
                        fromView.alpha = 0
                    },
                        completion: { finished in
                            if finished {
                                transitionContext.completeTransition(true)
                            }
                    })
                } else {
                    UIView.animate(withDuration: 0.2, animations: {
                        fromView.center = .init(x: fromView.center.x, y: UIScreen.main.bounds.height*1.5)
                    },
                        completion: { finished in
                            if finished {
                                transitionContext.completeTransition(true)
                            }
                    })
                }
            }
        
    }

    //第四步 UIPresentationController

    /// For custom modal transition styles, you can provide a UIPresentationController object in addition to the animator objects. The system creates your presentation controller before presenting the view controller and keeps a reference to that object until the view controller is dismissed. Because its existence extends beyond the lifespan of either animator object, you can use the presentation controller to coordinate aspects of the presentation or dismissal process that would be difficult to do otherwise. For example, if your custom transition style involves displaying a separate shadow view as a backdrop to the view controller’s content, the presentation controller can create the shadow view and show it and hide it at the appropriate times.
    class DqPresentationController: UIPresentationController {
        
        var blur:UIVisualEffect!
        var blurView:UIVisualEffectView!
        
        
        override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
            
            super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
            blur = UIBlurEffect(style: UIBlurEffect.Style.dark)
            blurView = UIVisualEffectView()
        }
        
        override var frameOfPresentedViewInContainerView: CGRect{
            return CGRect(x: (kScreenWith - 200)/2, y: (kScreenHieght - 200)/2,  200, height: 200)
        }
        
        override func containerViewDidLayoutSubviews() {
             if let containerView = containerView {
               blurView.frame = containerView.bounds
           } else {
                blurView.frame = UIScreen.main.bounds
           }
        }
        override func presentationTransitionWillBegin() {
            containerView?.addSubview(blurView)
            UIView.animate(withDuration: 0.6, animations: {
                self.blurView.effect = self.blur
            }) { (finish) in
                
            }
            
        }
        
        override func dismissalTransitionWillBegin() {
            UIView.animate(withDuration: 0.6, animations: {
                self.blurView.effect = nil
            }) { (finish) in
                self.blurView.isHidden = true
            }
        }
        
        override func dismissalTransitionDidEnd(_ completed: Bool) {
            blurView.removeFromSuperview()
        }
        
    }
  • 相关阅读:
    JavaScript 深入之从原型到原型链
    js重写内置的call、apply、bind
    js中flat方法的实现原理
    【我的物联网成长记6】由浅入深了解NB-IoT【华为云技术分享】
    GO富集分析示例【华为云技术分享】
    华为“方舟编译器”到底是啥?一文看懂TA如何让手机性能再突破【华为云技术分享】
    无码系列-7-代码的语文修养_上篇【华为云技术分享】
    机器学习笔记(一)----基本概念【华为云技术分享】
    性能达到原生 MySQL 七倍,华为云 Taurus 技术解读【华为云技术分享】
    【立即报名】人脸情绪识别案例分享【华为云技术分享】
  • 原文地址:https://www.cnblogs.com/duzhaoquan/p/12727100.html
Copyright © 2011-2022 走看看