美文网首页iOS新手学习Swift学习
iOS自定义转场动画 | UIViewControllerAni

iOS自定义转场动画 | UIViewControllerAni

作者: Grabin | 来源:发表于2018-07-28 08:55 被阅读42次

    先来个有用的教程 https://www.raywenderlich.com/170144/custom-uiviewcontroller-transitions-getting-started

    总结了下UIKit关于转场动画的运行机制:
    image.png
    demo效果:
    animation.gif
    一、过渡动画(UIViewControllerAnimatedTransitioning)
    1.(左边ViewController)首先得创建一个过渡动画(即非交互式转场动画):
    animation.gif
    · 创建一个类,继承NSObject,然后使它遵守UIViewControllerAnimatedTransitioning并实现代理方法。
    image.png
    import UIKit
    
    class LeftDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
        
        override init() {
            super.init()
        }
        
        func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
            return 0.5
        }
        
        func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
            guard let fromVC = transitionContext.viewController(forKey: .from),
                let toVC = transitionContext.viewController(forKey: .to),
                let fromView = fromVC.view,
                let toView = toVC.view  else { return }
            
            transitionContext.containerView.addSubview(toView)
            
            let width = UIScreen.main.bounds.size.width
            let height = UIScreen.main.bounds.size.height
            let duration = transitionDuration(using: transitionContext)
            fromView.frame = CGRect(x: 0, y: 0, width: width, height: height)
            toView.frame = CGRect(x: width, y: 0, width: width, height: height)
            UIView.animate(withDuration: duration, animations: {
                fromView.frame = CGRect(x: -width, y: 0, width: width, height: height)
                toView.frame = CGRect(x: 0, y: 0, width: width, height: height)
            }) { (finished) in
                fromView.transform = CGAffineTransform.identity
                toView.transform = CGAffineTransform.identity
                let isCancelled = transitionContext.transitionWasCancelled
                transitionContext.completeTransition(!isCancelled)
            }
        }
    
    }
    
    
    · 使用

    假设场景是:当前ViewController要present到左边leftViewController,那么在当前ViewController中,实现leftViewController的transitioningDelegate的代理方法。(注意是当前ViewController中)


    image.png
    import UIKit
    
    class ViewController: UIViewController {
       
        lazy var rightVC = RightViewController()
        
        lazy var leftVC = LeftViewController()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            rightVC.transitioningDelegate = self
            leftVC.transitioningDelegate = self
        }
    
        @IBAction func leftBtnAction(_ sender: UIButton) {
            present(leftVC, animated: true, completion: nil)
        }
        
        @IBAction func rightBtnAction(_ sender: UIButton) {
            present(rightVC, animated: true, completion: nil)
        }
        
        
    }
    
    extension ViewController: UIViewControllerTransitioningDelegate {
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            guard let revealVC = source as? ViewController  else { return nil }
            if let _ = presented as? LeftViewController {
                return LeftPresentAnimationController()
            }
            return nil
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return nil
        }
        
        func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
            return nil
        }
        
        func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
            return nil
        }
    }
    
    

    这样就可以得到一个present的自定义过渡动画。


    animation.gif
    二、实现交互式转场,很简单地理解成有一个特殊的工具类,在有过渡动画的基础上,通过手势的交互,去控制过渡动画的进度。而这个类,就是UIPercentDrivenInteractiveTransition。
    · 首先,创建一个类,让它继承UIPercentDrivenInteractiveTransition()注意是继承。这个类通过手势交互,去控制过渡动画的进度。所以在这个类里面我们需要拿到对应的ViewController,去添加手势,所以在初始化的时候,需要把ViewController带进来。
    import UIKit
    
    class LeftPresentInterationController: UIPercentDrivenInteractiveTransition {
        var interactionInProgress = false
        
        private var shouldCompleteTransition = false
        private weak var viewController: UIViewController!
        private weak var toViewController: UIViewController!
        
        init(viewController: UIViewController, toViewController: UIViewController) {
            super.init()
            self.viewController = viewController
            self.toViewController = toViewController
            prepareGestureRecognizer(in: viewController.view)
        }
        
        private func prepareGestureRecognizer(in view: UIView) {
            let gesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handleGesture(_:)))
            gesture.edges = .left
            view.addGestureRecognizer(gesture)
        }
        
        @objc func handleGesture(_ gestureRecognizer: UIScreenEdgePanGestureRecognizer) {
            
            let translation = gestureRecognizer.translation(in: gestureRecognizer.view?.superview)
            var progress = translation.x / UIScreen.main.bounds.size.width
            progress = CGFloat(fminf(fmaxf(Float(progress), 0.0), 1.0))
            
            switch gestureRecognizer.state {
            case .began:
                interactionInProgress = true
                viewController.present(toViewController, animated: true, completion: nil)
            case .changed:
                shouldCompleteTransition = progress > 0.5
                update(progress)
            case .cancelled:
                interactionInProgress = false
                cancel()
            case .ended:
                interactionInProgress = false
                if shouldCompleteTransition {
                    finish()
                } else {
                    cancel()
                }
            default:
                break
            }
            
        }
    }
    
    
    · 然后在当前ViewController中,实现可交互动画的代理。
    //
    //  ViewController.swift
    //  TransitionAnimationDemo
    //
    //  Created by grwong on 2018/7/24.
    //  Copyright © 2018年 grwong. All rights reserved.
    //
    
    import UIKit
    
    class ViewController: UIViewController {
        
        var rightPresentInteractionController: RightPresentInterationController?
        
        var leftPresentInterationController: LeftPresentInterationController?
        
        lazy var rightVC = RightViewController()
        
        lazy var leftVC = LeftViewController()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            rightVC.transitioningDelegate = self
            leftVC.transitioningDelegate = self
            rightPresentInteractionController = RightPresentInterationController(viewController: self, toViewController: rightVC)
            leftPresentInterationController = LeftPresentInterationController(viewController: self, toViewController: leftVC)
        }
    
        @IBAction func leftBtnAction(_ sender: UIButton) {
            present(leftVC, animated: true, completion: nil)
        }
        
        @IBAction func rightBtnAction(_ sender: UIButton) {
    //        let rightVC = RightViewController()
            
            present(rightVC, animated: true, completion: nil)
        }
        
        
    }
    
    extension ViewController: UIViewControllerTransitioningDelegate {
        func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            guard let revealVC = source as? ViewController  else { return nil }
            if let _ = presented as? LeftViewController {
                return LeftPresentAnimationController(interactionController: revealVC.leftPresentInterationController)
            }
            return nil
        }
        
        func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
            return nil
        }
        
        func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
            return nil
        }
        
        func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
           if let animator = animator as? LeftPresentAnimationController,
                let interationController = animator.interactionController,
                interationController.interactionInProgress {
                return interationController
            }
            return nil
        }
    }
    
    
    

    就可以实现拖动效果


    placeholder.gif
    完整的demo在github上 >>> TransitionAnimationDemo

    相关文章

      网友评论

        本文标题:iOS自定义转场动画 | UIViewControllerAni

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