Created
December 19, 2021 23:09
-
-
Save thomsmed/6a5a50ba0a735178f11cbd232552f5f9 to your computer and use it in GitHub Desktop.
FullScreenAnimationController.swift - From "Transition images to full screen animated" @ medium.com
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // FullScreenAnimationController.swift | |
| // | |
| import Foundation | |
| import UIKit | |
| import TinyConstraints | |
| final class FullScreenAnimationController: NSObject, UIViewControllerAnimatedTransitioning { | |
| fileprivate enum AnimationType { | |
| case present | |
| case dismiss | |
| } | |
| private let animationType: AnimationType | |
| private let animationDuration: TimeInterval | |
| private weak var anchorView: UIView? | |
| private let anchorViewCenter: CGPoint | |
| private let anchorViewSize: CGSize | |
| private let anchorViewTag: Int | |
| private var propertyAnimator: UIViewPropertyAnimator? | |
| fileprivate init(animationType: AnimationType, animationDuration: TimeInterval = 0.3, anchorView: UIView?) { | |
| self.animationType = animationType | |
| self.anchorView = anchorView | |
| self.animationDuration = animationDuration | |
| if let anchorView = anchorView { | |
| anchorViewCenter = anchorView.superview?.convert(anchorView.center, to: nil) ?? .zero | |
| anchorViewSize = anchorView.bounds.size | |
| anchorViewTag = anchorView.tag | |
| } else { | |
| anchorViewCenter = .zero | |
| anchorViewSize = .zero | |
| anchorViewTag = 0 | |
| } | |
| } | |
| func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { | |
| animationDuration | |
| } | |
| func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { | |
| switch animationType { | |
| case .present: | |
| guard | |
| let toViewController = transitionContext.viewController(forKey: .to) | |
| else { | |
| return transitionContext.completeTransition(false) | |
| } | |
| transitionContext.containerView.insertSubview(toViewController.view, at: 1) // In between the presentations controller's background and close button | |
| toViewController.view.edgesToSuperview() | |
| toViewController.view.layoutIfNeeded() | |
| propertyAnimator = presentAnimator(with: transitionContext, animating: toViewController) | |
| case .dismiss: | |
| guard | |
| let fromViewController = transitionContext.viewController(forKey: .from) | |
| else { | |
| return transitionContext.completeTransition(false) | |
| } | |
| propertyAnimator = dismissAnimator(with: transitionContext, animating: fromViewController) | |
| } | |
| } | |
| private func presentAnimator(with transitionContext: UIViewControllerContextTransitioning, | |
| animating viewController: UIViewController) -> UIViewPropertyAnimator { | |
| let view: UIView = viewController.view.viewWithTag(anchorViewTag) ?? viewController.view | |
| let finalSize = view.bounds.size | |
| let finalCenter = view.center | |
| view.transform = CGAffineTransform(scaleX: anchorViewSize.width / finalSize.width, | |
| y: anchorViewSize.height / finalSize.height) | |
| view.center = view.superview!.convert(anchorViewCenter, from: nil) | |
| anchorView?.isHidden = true | |
| return UIViewPropertyAnimator.runningPropertyAnimator(withDuration: transitionDuration(using: transitionContext), delay: 0, options: [.curveEaseInOut], animations: { | |
| view.transform = .identity | |
| view.center = finalCenter | |
| }, completion: { _ in | |
| transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
| }) | |
| } | |
| private func dismissAnimator(with transitionContext: UIViewControllerContextTransitioning, | |
| animating viewController: UIViewController) -> UIViewPropertyAnimator { | |
| let view: UIView = viewController.view.viewWithTag(anchorViewTag) ?? viewController.view | |
| let initialSize = view.bounds.size | |
| let finalCenter = view.superview!.convert(anchorViewCenter, from: nil) | |
| let finalTransform = CGAffineTransform(scaleX: self.anchorViewSize.width / initialSize.width, | |
| y: self.anchorViewSize.height / initialSize.height) | |
| return UIViewPropertyAnimator.runningPropertyAnimator(withDuration: transitionDuration(using: transitionContext), delay: 0, options: [.curveEaseInOut], animations: { | |
| view.transform = finalTransform | |
| view.center = finalCenter | |
| }, completion: { _ in | |
| self.anchorView?.isHidden = false | |
| transitionContext.completeTransition(!transitionContext.transitionWasCancelled) | |
| }) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment