metatext/Transitions/ZoomAnimator.swift

138 lines
5.9 KiB
Swift
Raw Permalink Normal View History

2020-10-22 05:05:50 +00:00
// Copyright © 2020 Metabolist. All rights reserved.
import UIKit
2022-05-06 01:14:23 +00:00
protocol ZoomAnimatorDelegate: AnyObject {
2020-10-22 05:05:50 +00:00
func transitionWillStartWith(zoomAnimator: ZoomAnimator)
func transitionDidEndWith(zoomAnimator: ZoomAnimator)
func referenceView(for zoomAnimator: ZoomAnimator) -> UIView?
func referenceViewFrameInTransitioningView(for zoomAnimator: ZoomAnimator) -> CGRect?
}
2020-11-09 06:22:20 +00:00
final class ZoomAnimator: NSObject {
2020-10-22 05:05:50 +00:00
weak var fromDelegate: ZoomAnimatorDelegate?
weak var toDelegate: ZoomAnimatorDelegate?
var transitionView: UIView?
var isPresenting = true
}
extension ZoomAnimator: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
isPresenting ? .defaultAnimationDuration : .shortAnimationDuration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
fromDelegate?.transitionWillStartWith(zoomAnimator: self)
toDelegate?.transitionWillStartWith(zoomAnimator: self)
if isPresenting {
animateZoomInTransition(using: transitionContext)
} else {
animateZoomOutTransition(using: transitionContext)
}
}
}
private extension ZoomAnimator {
private func animateZoomInTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard
let toVC = transitionContext.viewController(forKey: .to),
let fromVC = transitionContext.viewController(forKey: .from),
let fromReferenceView = fromDelegate?.referenceView(for: self),
let toReferenceView = toDelegate?.referenceView(for: self),
let fromReferenceViewFrame = fromDelegate?.referenceViewFrameInTransitioningView(for: self)
else { return }
toVC.view.alpha = 0
2021-03-05 00:53:49 +00:00
toVC.view.frame = transitionContext.finalFrame(for: toVC)
2020-10-22 05:05:50 +00:00
toReferenceView.isHidden = true
transitionContext.containerView.addSubview(toVC.view)
if transitionView == nil, let transitionView = (fromReferenceView as? ZoomAnimatableView)?.transitionView() {
transitionView.frame = fromReferenceViewFrame
2021-01-04 07:17:38 +00:00
transitionView.layer.contentsRect = fromReferenceView.layer.contentsRect
transitionView.layer.cornerRadius = fromReferenceView.layer.cornerRadius
2020-10-22 05:05:50 +00:00
self.transitionView = transitionView
transitionContext.containerView.addSubview(transitionView)
}
fromReferenceView.isHidden = true
2021-02-06 21:52:08 +00:00
let referenceViewFrame = (fromReferenceView as? ZoomAnimatableView)?.frame(inView: toVC.view) ?? .zero
let finalTransitionFrame = referenceViewFrame.containsNaN ? .zero : referenceViewFrame
2020-10-22 05:05:50 +00:00
UIView.animate(
withDuration: transitionDuration(using: transitionContext),
delay: 0,
usingSpringWithDamping: 0.8,
initialSpringVelocity: 0,
options: [.transitionCrossDissolve]) {
2021-02-06 21:52:08 +00:00
self.transitionView?.frame = finalTransitionFrame
2021-01-04 07:17:38 +00:00
self.transitionView?.layer.contentsRect = .defaultContentsRect
self.transitionView?.layer.cornerRadius = 0
2020-10-22 05:05:50 +00:00
toVC.view.alpha = 1.0
fromVC.tabBarController?.tabBar.alpha = 0
} completion: { _ in
self.transitionView?.removeFromSuperview()
toReferenceView.isHidden = false
fromReferenceView.isHidden = false
self.transitionView = nil
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
self.toDelegate?.transitionDidEndWith(zoomAnimator: self)
self.fromDelegate?.transitionDidEndWith(zoomAnimator: self)
}
}
private func animateZoomOutTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
guard
let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to),
let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
let fromReferenceView = fromDelegate?.referenceView(for: self),
let fromReferenceViewFrame = fromDelegate?.referenceViewFrameInTransitioningView(for: self)
else { return }
let toReferenceView = toDelegate?.referenceView(for: self)
let toReferenceViewFrame = toDelegate?.referenceViewFrameInTransitioningView(for: self)
toReferenceView?.isHidden = true
if transitionView == nil, let transitionView = (fromReferenceView as? ZoomAnimatableView)?.transitionView() {
transitionView.frame = fromReferenceViewFrame
self.transitionView = transitionView
containerView.addSubview(transitionView)
}
containerView.insertSubview(toVC.view, belowSubview: fromVC.view)
fromReferenceView.isHidden = true
UIView.animate(
withDuration: transitionDuration(using: transitionContext)) {
fromVC.view.alpha = 0
if let toReferenceViewFrame = toReferenceViewFrame {
self.transitionView?.frame = toReferenceViewFrame
} else {
self.transitionView?.alpha = 0
}
2021-01-04 07:17:38 +00:00
self.transitionView?.layer.contentsRect = toReferenceView?.layer.contentsRect ?? .defaultContentsRect
self.transitionView?.layer.cornerRadius = toReferenceView?.layer.cornerRadius ?? 0
2021-01-04 07:17:38 +00:00
2020-10-22 05:05:50 +00:00
toVC.tabBarController?.tabBar.alpha = 1
} completion: { _ in
self.transitionView?.removeFromSuperview()
toReferenceView?.isHidden = false
fromReferenceView.isHidden = false
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
self.toDelegate?.transitionDidEndWith(zoomAnimator: self)
self.fromDelegate?.transitionDidEndWith(zoomAnimator: self)
}
}
}