码迷,mamicode.com
首页 > 其他好文 > 详细

自定义Controller转场动画

时间:2020-04-18 18:30:18      阅读:64      评论:0      收藏:0      [点我收藏+]

标签:err   min   aspect   from   print   completed   rac   stat   nap   

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

//一 创建控制器
class TransitionViewController: UIViewController {

    var endVelocity: CGPoint?
    let imageView = UIImageView(frame: CGRect(x: 25, y: 25, width: 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(width: 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, width: 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()
    }
    
}

 

自定义Controller转场动画

标签:err   min   aspect   from   print   completed   rac   stat   nap   

原文地址:https://www.cnblogs.com/duzhaoquan/p/12727100.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!