title: additionalSafeAreaInsets is not accounted for during view controller dismissal, using custom UIViewControllerTransitioningDelegate
body: <p>So, straight to the problem:</p>
  <p>I've created a custom <strong>UIViewControllerTransitioningDelegate</strong> that I use to animate a view from one view controller, to full-screen in another view controller. Im doing this by creating <strong>UIViewControllerAnimatedTransitioning</strong>-objects that animate the presented view's frame. And it works great! Except when I try to adjust the <strong>additionalSafeAreaInsets</strong> of the view controller owning the view during dismissal...</p>
  <p>It looks like this property is not accounted for when I'm trying to animate the dismissal of the view controller and its view. It works fine during presentation.</p>
  <p>The gif below shows how it looks. The red box is the safe area (plus some padding) of the presented view - which I'm trying to compensate for during animation, using the <strong>additionalSafeAreaInsets</strong> property of the view controller owning the view.</p>
  <p><img src="https://i.stack.imgur.com/OsfHg.gif" alt="additionalSafeAreaInsets only accounted for during presentation" /></p>
  <p>As the gif shows, the safe area is properly adjusted during presentation but not during dismissal.</p>
  <p>So, what I want is: use <strong>additionalSafeAreaInsets</strong> to diminish the effect of the safe area during animation, by setting <strong>additionalSafeAreaInsets</strong> to the &quot;inverted&quot; values of the safe area. So that the effective safe area starts at 0 and &quot;animates&quot; to the expected value during presentation, and starts at expected value and &quot;animates&quot; to 0 during dismissal.
  (I'm quoting &quot;animates&quot;, since its actually the view's frame that is animated. But UIKit/Auto Layout use these properties when calculating the frames)</p>
  <p>Any thoughts on how to battle this issue is great welcome!</p>
  <p>The code for the custom UIViewControllerTransitioningDelegate is provided below.</p>
  <pre><code>//
  //  FullScreenTransitionManager.swift
  //
  
  import Foundation
  import UIKit
  
  // MARK: FullScreenPresentationController
  
  final class FullScreenPresentationController: UIPresentationController {
      private let backgroundView: UIView = {
          let view = UIView()
          view.backgroundColor = .systemBackground
          view.alpha = 0
          return view
      }()
      
      private lazy var tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(onTap))
      
      @objc private func onTap(_ gesture: UITapGestureRecognizer) {
          presentedViewController.dismiss(animated: true)
      }
  }
      
  // MARK: UIPresentationController
      
  extension FullScreenPresentationController {
      override func presentationTransitionWillBegin() {
          guard let containerView = containerView else { return }
          
          containerView.addGestureRecognizer(tapGestureRecognizer)
          
          containerView.addSubview(backgroundView)
          backgroundView.frame = containerView.frame
          
          guard let transitionCoordinator = presentingViewController.transitionCoordinator else { return }
          
          transitionCoordinator.animate(alongsideTransition: { context in
              self.backgroundView.alpha = 1
          })
      }
      
      override func presentationTransitionDidEnd(_ completed: Bool) {
          if !completed {
              backgroundView.removeFromSuperview()
              containerView?.removeGestureRecognizer(tapGestureRecognizer)
          }
      }
      
      override func dismissalTransitionWillBegin() {
          guard let transitionCoordinator = presentingViewController.transitionCoordinator else { return }
          
          transitionCoordinator.animate(alongsideTransition: { context in
              self.backgroundView.alpha = 0
          })
      }
      
      override func dismissalTransitionDidEnd(_ completed: Bool) {
          if completed {
              backgroundView.removeFromSuperview()
              containerView?.removeGestureRecognizer(tapGestureRecognizer)
          }
      }
      
      override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
          guard
              let containerView = containerView,
              let presentedView = presentedView
          else { return }
          coordinator.animate(alongsideTransition: { context in
              self.backgroundView.frame = containerView.frame
              presentedView.frame = self.frameOfPresentedViewInContainerView
          })
      }
  }
  
  // MARK: FullScreenTransitionManager
  
  final class FullScreenTransitionManager: NSObject, UIViewControllerTransitioningDelegate {
      private weak var anchorView: UIView?
      
      init(anchorView: UIView) {
          self.anchorView = anchorView
      }
      
      func presentationController(forPresented presented: UIViewController,
                                  presenting: UIViewController?,
                                  source: UIViewController) -&gt; UIPresentationController? {
          FullScreenPresentationController(presentedViewController: presented, presenting: presenting)
      }
      
      func animationController(forPresented presented: UIViewController,
                               presenting: UIViewController,
                               source: UIViewController) -&gt; UIViewControllerAnimatedTransitioning? {
          let anchorFrame = anchorView?.safeAreaLayoutGuide.layoutFrame ?? CGRect(origin: presented.view.center, size: .zero)
          return FullScreenAnimationController(animationType: .present,
                                               anchorFrame: anchorFrame)
      }
      
      func animationController(forDismissed dismissed: UIViewController) -&gt; UIViewControllerAnimatedTransitioning? {
          let anchorFrame = anchorView?.safeAreaLayoutGuide.layoutFrame ?? CGRect(origin: dismissed.view.center, size: .zero)
          return FullScreenAnimationController(animationType: .dismiss,
                                               anchorFrame: anchorFrame)
      }
  }
  
  // MARK: UIViewControllerAnimatedTransitioning
  
  final class FullScreenAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
      enum AnimationType {
          case present
          case dismiss
      }
      
      private let animationType: AnimationType
      private let anchorFrame: CGRect
      private let animationDuration: TimeInterval
      private var propertyAnimator: UIViewPropertyAnimator?
      
      init(animationType: AnimationType, anchorFrame: CGRect, animationDuration: TimeInterval = 0.3) {
          self.animationType = animationType
          self.anchorFrame = anchorFrame
          self.animationDuration = animationDuration
      }
      
      func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -&gt; 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.addSubview(toViewController.view)
              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) -&gt; UIViewPropertyAnimator {
          let finalFrame = transitionContext.finalFrame(for: viewController)
          let safeAreaInsets = transitionContext.containerView.safeAreaInsets
          let safeAreaCompensation = UIEdgeInsets(top: -safeAreaInsets.top,
                                                  left: -safeAreaInsets.left,
                                                  bottom: -safeAreaInsets.bottom,
                                                  right: -safeAreaInsets.right)
          viewController.additionalSafeAreaInsets = safeAreaCompensation
          viewController.view.frame = anchorFrame
          viewController.view.setNeedsLayout()
          viewController.view.layoutIfNeeded()
          return UIViewPropertyAnimator.runningPropertyAnimator(withDuration: transitionDuration(using: transitionContext), delay: 0, options: [.curveEaseInOut, .layoutSubviews], animations: {
              viewController.additionalSafeAreaInsets = .zero
              viewController.view.frame = finalFrame
              viewController.view.setNeedsLayout()
              viewController.view.layoutIfNeeded()
          }, completion: { _ in
              transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
          })
      }
      
      private func dismissAnimator(with transitionContext: UIViewControllerContextTransitioning,
                                   animating viewController: UIViewController) -&gt; UIViewPropertyAnimator {
          let finalFrame = anchorFrame
          let safeAreaInsets = transitionContext.containerView.safeAreaInsets
          let safeAreaCompensation = UIEdgeInsets(top: -safeAreaInsets.top,
                                                  left: -safeAreaInsets.left,
                                                  bottom: -safeAreaInsets.bottom,
                                                  right: -safeAreaInsets.right)
          viewController.view.setNeedsLayout()
          viewController.view.layoutIfNeeded()
          return UIViewPropertyAnimator.runningPropertyAnimator(withDuration: transitionDuration(using: transitionContext), delay: 0, options: [.curveEaseInOut, .layoutSubviews], animations: {
              viewController.additionalSafeAreaInsets = safeAreaCompensation
              viewController.view.frame = finalFrame
              viewController.view.setNeedsLayout()
              viewController.view.layoutIfNeeded()
          }, completion: { _ in
              transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
          })
      }
  }
  
  </code></pre>