CustomTransitionContainerViewController

Updated
Aug 15, 2021 8:41 AM
Created
May 30, 2021 7:11 AM
Tags
SwiftUIKitMemo
Keywords
Date

An abstract view controller to enable custom trantision for presentation and dismissal.

import Foundation

open class CustomTransitionContainerViewController: UIViewController, UIViewControllerTransitioningDelegate, UIGestureRecognizerDelegate, ModalPresentable {

  // MARK: - Properties

  public override var childForStatusBarStyle: UIViewController? {
    return bodyViewController
  }

  public override var childForStatusBarHidden: UIViewController? {
    return bodyViewController
  }

  public let bodyViewController: UIViewController?

  public var presentationTransition: (() -> UIViewControllerAnimatedTransitioning)?
  public var dismissalTransition: (() -> UIViewControllerAnimatedTransitioning)?

  // MARK: - Initializers

  /// Creates an instance
  ///
  /// - Parameters:
  ///   - idiom:
  ///   - bodyViewController: a view controller that displays as a child view controller. It helps a case of can't create a subclass of FluidViewController.
  public init(
    bodyViewController: UIViewController? = nil
  ) {

    self.bodyViewController = bodyViewController
    super.init(nibName: nil, bundle: nil)

    modalPresentationStyle = .fullScreen
    transitioningDelegate = self
    modalPresentationCapturesStatusBarAppearance = true
  }

  @available(*, unavailable)
  public required init?(
    coder: NSCoder
  ) {
    fatalError()
  }

  // MARK: - Functions

  open override func viewDidLoad() {
    super.viewDidLoad()

    if let bodyViewController = bodyViewController {
      addChild(bodyViewController)
      view.addSubview(bodyViewController.view)
      NSLayoutConstraint.activate([
        bodyViewController.view.topAnchor.constraint(equalTo: view.topAnchor),
        bodyViewController.view.rightAnchor.constraint(equalTo: view.rightAnchor),
        bodyViewController.view.leftAnchor.constraint(equalTo: view.leftAnchor),
        bodyViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
      ])
      bodyViewController.didMove(toParent: self)
    }
  }

  public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {

    assert([.fullScreen, .overFullScreen, .custom].contains(modalPresentationStyle))

    return presentationTransition?()

  }

  public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {

    assert([.fullScreen, .overFullScreen, .custom].contains(modalPresentationStyle))

    return dismissalTransition?()

  }

}