美文网首页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