美文网首页
关于自定义转场效果(transitioningDelegate)

关于自定义转场效果(transitioningDelegate)

作者: 91阿生 | 来源:发表于2021-12-22 09:19 被阅读0次

    第一种:没有动画效果跳转

    效果图:


    无动画效果.gif
    从 AViewController -> BViewController
    
    @objc func toBViewController() {
        let bVC = BViewController()
        // 注意:设置目标控制器 transition 转场效果代理. self: AViewController
        bVC.transitioningDelegate = self
        self.present(bVC, animated: true, completion: nil)
     }
    
    // MARK: - UIViewControllerTransitioningDelegate
    extension HomeViewController: UIViewControllerTransitioningDelegate {
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return self
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return self
        }
    }
    
    // MARK: - UIViewControllerAnimatedTransitioning 关于取消 present 效果跳转(无动画效果)
    extension HomeViewController: UIViewControllerAnimatedTransitioning {
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.5
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            // 关于取消 present 效果跳转(无动画效果)
            guard let toView = transitionContext.view(forKey: .to) else {
                transitionContext.completeTransition(true)
                return
            }
            transitionContext.containerView.addSubview(toView)
            transitionContext.completeTransition(true)
        }
    }
    

    第二种:类似 push、pop动画效果跳转

    效果图:


    类似 push/pop效果.gif
    从 AViewController -> BViewController
    
    enum TransitionType {
        case present
        case dismiss
    }
    
    @objc func toBViewController() {
        let bVC = BViewController()
        // 注意:设置目标控制器 transition 转场效果代理. self: AViewController
        bVC.transitioningDelegate = self
        self.present(bVC, animated: true, completion: nil)
     }
    
    // MARK: - UIViewControllerTransitioningDelegate
    extension HomeViewController: UIViewControllerTransitioningDelegate {
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            self.type = .present
            return self
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            self.type = .dismiss
            return self
        }
    }
    
    // MARK: - UIViewControllerAnimatedTransitioning 关于自定义转场动效(push / pop 效果,push:从右->左;pop:从左->右)
    extension HomeViewController: UIViewControllerAnimatedTransitioning {
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.5
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            guard let toView = transitionContext.view(forKey: .to),
                  let fromView = transitionContext.view(forKey: .from) else {
                transitionContext.completeTransition(true)
                return
            }
            // 呈现在当前屏幕上的 vc 则为 from;目标 vc 则为to
            
            switch self.type {
            case .present:
                transitionContext.containerView.addSubview(toView)
                toView.transform = CGAffineTransform(translationX: self.view.bounds.width, y: 0)
                
                UIView.animate(withDuration: transitionDuration(using: nil)) {
                    toView.transform = .identity
                } completion: { _ in
                    transitionContext.completeTransition(true)
                }
            case .dismiss:
                // 将 toView 放置最底层,fromView平移后,就会看到 toview;如果直接 add toView,则效果会一闪,看不到 fromView 平移效果。原因:add toView 后被 toView 遮住了。
                // 因此使用 insertSubview
                transitionContext.containerView.insertSubview(toView, at: 0)
                UIView.animate(withDuration: transitionDuration(using: nil)) {
                    fromView.transform = CGAffineTransform(translationX: self.view.bounds.width, y: 0)
                } completion: { _ in
                    transitionContext.completeTransition(true)
                }
            }
        }
    }
    

    第三种:类似 淘宝展示商品 动画效果跳转

    效果图:


    商品.gif
    @objc func toBViewController() {
        let bVC = BViewController()
        // 注意:设置目标控制器 transition 转场效果代理. self: AViewController
        bVC.transitioningDelegate = self
        bVC.view.frame = CGRect(x: 0, y: self.view.bounds.height - detailViewHeight, width: self.view.bounds.width, height: detailViewHeight)
        self.present(bVC, animated: true, completion: nil)
     }
        
     @objc func tapFromView() {
        self.dismiss(animated: true, completion: nil)
     }
    
    // MARK: - UIViewControllerTransitioningDelegate
    extension HomeViewController: UIViewControllerTransitioningDelegate {
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            self.type = .present
            return self
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            self.type = .dismiss
            return self
        }
    }
    
    // MARK: - UIViewControllerAnimatedTransitioning 关于淘宝展示商品信息效果转场效果
    extension HomeViewController: UIViewControllerAnimatedTransitioning {
       func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
           return 1
       }
    
       func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            // 关于取消 present 效果跳转(无动画效果)
            guard let toView = transitionContext.view(forKey: .to),
                  let fromView = transitionContext.view(forKey: .from) else {
                transitionContext.completeTransition(true)
                return
            }
    
            switch self.type {
            case .present:
                transitionContext.containerView.addSubview(toView)
                // 设置商品 VC 效果
                var transition3D = CATransform3DIdentity
                // CATransform3D 的 m34 元素,用来做透视(有 3D 效果);
                // m34 为-1.0 / d 来应用透视效果; d = 通常500~1000
                // 注意:得先设置
                transition3D.m34 = -1 / 1000
                // 绕 x 轴3D旋转 pi/5
                transition3D = CATransform3DRotate(transition3D, .pi / 8, 1, 0, 0)
                // 防止 fromView 旋转后遮住 toView; fromView平移(z轴方向)
                transition3D = CATransform3DTranslate(transition3D, 0, 0, -200)
    
                UIView.animate(withDuration: transitionDuration(using: nil)) {
                    fromView.layer.transform = transition3D
                } completion: { _ in
                    // 再进行缩放
                    UIView.animate(withDuration: self.transitionDuration(using: nil)) {
                        fromView.layer.transform = CATransform3DMakeScale(0.9, 0.9, 1)
                    }
                }
    
                // toView 动画
                toView.transform = CGAffineTransform(translationX: 0, y: toView.bounds.height)
                UIView.animate(withDuration: transitionDuration(using: nil)*2) {
                    toView.transform = .identity
                } completion: { _ in
                    // 由于 completeTransition 后会出现 fromView 被移除,因此需要截图 代替 fromView
    
                    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, false, 0)
                    // 截取当前屏幕
                    self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: false)
                    // 截取的当前UIView转成UIImage
                    let image = UIGraphicsGetImageFromCurrentImageContext()
                    UIGraphicsEndImageContext()
    
                    let replaceImageView = UIImageView(image: image)
                    replaceImageView.isUserInteractionEnabled = true
                    replaceImageView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
    
                    let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapFromView))
                    replaceImageView.addGestureRecognizer(tap)
    
    
                    transitionContext.containerView.insertSubview(replaceImageView, at: 0)
                    transitionContext.completeTransition(true)
                }
    
            case .dismiss:
                transitionContext.containerView.addSubview(fromView)
                UIView.animate(withDuration: transitionDuration(using: nil)) {
                    fromView.transform = CGAffineTransform(translationX: 0, y: fromView.bounds.height)
                } completion: { _ in
                    UIView.animate(withDuration: self.transitionDuration(using: nil)*0.5) {
                        toView.transform = .identity
                    }
                    transitionContext.completeTransition(true)
                }
            }
       }
    }
    
    

    相关文章

      网友评论

          本文标题:关于自定义转场效果(transitioningDelegate)

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