先来个有用的教程 https://www.raywenderlich.com/170144/custom-uiviewcontroller-transitions-getting-started
总结了下UIKit关于转场动画的运行机制:
image.pngdemo效果:
animation.gif一、过渡动画(UIViewControllerAnimatedTransitioning)
1.(左边ViewController)首先得创建一个过渡动画(即非交互式转场动画):
animation.gif· 创建一个类,继承NSObject,然后使它遵守UIViewControllerAnimatedTransitioning并实现代理方法。
image.pngimport 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
网友评论