Skip to content
Snippets Groups Projects
FadeTransition.swift 2.86 KiB
Newer Older
Bruno Muniz's avatar
Bruno Muniz committed
import UIKit
import Combine
import SnapKit
import Shared

final class FadeTransition: NSObject, UIViewControllerAnimatedTransitioning {
    enum Direction {
        case present
        case dismiss
    }

    var direction: Direction = .present
    private let didDismiss: EmptyClosure
    private weak var darkOverlayView: UIControl?

    init(didDismiss: @escaping EmptyClosure) {
        self.didDismiss = didDismiss
        super.init()
    }

    func transitionDuration(using context: UIViewControllerContextTransitioning?) -> TimeInterval { 0.25 }

    func animateTransition(using context: UIViewControllerContextTransitioning) {
        switch direction {
        case .present:
            present(using: context)
        case .dismiss:
            dismiss(using: context)
        }
    }

    private func present(using context: UIViewControllerContextTransitioning) {
        guard let presentedView = context.view(forKey: .to) else {
            context.completeTransition(false)
            return
        }

        let darkOverlayView = UIControl()
        self.darkOverlayView = darkOverlayView

        darkOverlayView.alpha = 0.0
        darkOverlayView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        context.containerView.addSubview(darkOverlayView)
        darkOverlayView.frame = context.containerView.bounds

        context.containerView.addSubview(presentedView)
        presentedView.alpha = 0.0

        presentedView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
        presentedView.snp.makeConstraints { $0.edges.equalToSuperview() }

        UIView.animate(
            withDuration: transitionDuration(using: context),
            delay: 0,
            usingSpringWithDamping: 1,
            initialSpringVelocity: 0,
            options: .curveEaseInOut,
            animations: {
                darkOverlayView.alpha = 1.0
                presentedView.alpha = 1.0
                presentedView.transform = .identity
            },
            completion: { _ in
                context.completeTransition(true)
            })
    }

    private func dismiss(using context: UIViewControllerContextTransitioning) {
        guard let presentedView = context.view(forKey: .from) else {
            context.completeTransition(false)
            return
        }

        UIView.animate(
            withDuration: transitionDuration(using: context),
            delay: 0,
            usingSpringWithDamping: 1,
            initialSpringVelocity: 0,
            options: .curveEaseInOut,
            animations: { [weak darkOverlayView] in
                darkOverlayView?.alpha = 0.0
                presentedView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
                presentedView.alpha = 0.0
            },
            completion: { [weak self] _ in
                context.completeTransition(true)
                self?.didDismiss()
            })
    }
}