title: Trigger animation on Cancel when UIPercentDrivenInteractiveTransition ends half
body: <p>Is it a good practice to force custom transition back to original position for a view controller if the interaction ends and animation is cancelled. I have the following implementation which decides when to dismiss the view controller on pan gesture. If the pan gesture ends earlier, I was expecting to animate back to the original position like how it was presented before considering the duration to be proportional to the <code>progress</code> value on pan gesture</p>
  
  <pre><code>protocol AnimationControllerDelegate: AnyObject {
    func shouldHandlePanelInteractionGesture() -&gt; Bool
  }
  
  typealias PanGestureHandler = AnimationControllerDelegate &amp; UIViewController &amp; Animatable
  
  final class CustomInteractionController: UIPercentDrivenInteractiveTransition, UIGestureRecognizerDelegate {
      var interactionInProgress: Bool = false
      private var shouldCompleteTransition: Bool = false
      private var startTransitionY: CGFloat = 0
      private var panGestureRecognizer: UIPanGestureRecognizer?
      private weak var viewController: PanGestureHandler?
  
      func wireToViewController(viewController: Any) {
          guard let viewControllerDelegate = viewController as? PanGestureHandler else {
              return
          }
  
          self.viewController = viewControllerDelegate
  
          let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestureRecognizer(_:)))
  
          panGestureRecognizer = panGesture
          panGestureRecognizer?.delegate  = self
  
          self.viewController?.view.addGestureRecognizer(panGesture)
      }
  
      func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer,
                             shouldRecognizeSimultaneouslyWith
          otherGestureRecognizer: UIGestureRecognizer) -&gt; Bool {
          return true
      }
  
      @objc
      func handlePanGestureRecognizer(_ gestureRecognizer: UIPanGestureRecognizer) {
          guard let childView = gestureRecognizer.view,
              let parentView = childView.superview,
              let panGestureHandler = viewController else {
              return
          }
  
          switch gestureRecognizer.state {
          case .began:
              break
          case .changed:
              let translation = gestureRecognizer.translation(in: parentView)
              let velocity = gestureRecognizer.velocity(in: parentView)
              let state = gestureRecognizer.state
  
              if !panGestureHandler.shouldHandlePanelInteractionGesture() &amp;&amp; percentComplete == 0 {
                  return
              }
  
              let verticalMovement = translation.y / childView.bounds.height
              let downwardMovement = fmaxf(Float(verticalMovement), 0.0)
              let downwardMovementPercent = fminf(downwardMovement, 1.0)
              let progress = CGFloat(downwardMovementPercent)
  
              let alphaValue = (1 - progress) * 0.4
  
              panGestureHandler.shadowView.backgroundColor = Safety.Colors.backgroundViewColor(for: alphaValue)
  
              if abs(velocity.x) &gt; abs(velocity.y) &amp;&amp; state == .began {
                  return
              }
  
              if !interactionInProgress {
                  interactionInProgress = true
                  startTransitionY = translation.y
                  viewController?.dismiss(animated: true, completion: nil)
              } else {
                  shouldCompleteTransition = progress &gt; 0.3
                  update(progress)
              }
          case .cancelled:
              interactionInProgress = false
              startTransitionY = 0
              cancel()
          case .ended:
              interactionInProgress = false
              startTransitionY = 0
              if !shouldCompleteTransition {
                  // Can I call a custom transition here back to original position?
                  cancel()
              } else {
                  finish()
              }
          case .failed:
              interactionInProgress = false
              startTransitionY = 0
              cancel()
          default:
              break
          }
      }
  }
  </code></pre>