title: UIPercentDrivenInteractiveTransition yielding extraneous animation when done
body: <p>I'm using an interactive custom push transition with a <code>UIPercentDrivenInteractiveTransition</code>. The gesture recognizer successfully calls the interaction controller's <code>updateInteractiveTransition</code>. Likewise, the animation successfully completes when I call the interaction controller's <code>finishInteractiveTransition</code>. </p>
  
  <p>But, sometimes I get a extra bit of distracting animation at the end (where it seems to repeat the latter part of the animation). With reasonably simple animations, I rarely see this symptom on the iPhone 5 (though I routinely see it on the simulator when working on slow laptop). If I make the animation more computationally expensive (e.g. lots of shadows, multiple views animating different directions, etc.), the frequency of this problem on the device increases.</p>
  
  <p>Has anyone else seen this problem and figured out a solution other than streamlining the animations (which I admittedly should do anyway) and/or writing my own interaction controllers? The <code>UIPercentDrivenInteractiveTransition</code> approach has a certain elegance to it, but I'm uneasy with the fact that it misbehaves non-deterministically. Have others seen this behavior? Does anyone know of other solutions?</p>
  
  <p>To illustrate the effect, see the image below. Notice how the second scene, the red view, when the animation finishes, seems to repeat the latter part of its animation a second time.</p>
  
  <p><img src="https://i.stack.imgur.com/Uj0kI.gif" alt="animation not right"></p>
  
  <p>This animation is generated by:</p>
  
  <ul>
  <li><p>repeatedly calling <code>updateInteractiveTransition</code>, progressing update from 0% to 40%;</p></li>
  <li><p>momentarily pausing (so you can differentiate between the interactive transition and the completion animation resulting from <code>finishInteractiveTransition</code>);</p></li>
  <li><p>then calling <code>finishInteractiveTransition</code> to complete the animation; and</p></li>
  <li><p>the animation controller's animation's <code>completion</code> block calls <code>completeTransition</code> for the <code>transitionContext</code>, in order to clean everything up.</p></li>
  </ul>
  
  <p>Doing some diagnostics, it appears that it is this last step that triggers that extraneous bit of animation. The animation controller's completion block is called when the animation is finished, but as soon as I call <code>completeTransition</code>, it sometimes repeats the last bit of the animation (notably when using complex animations).</p>
  
  <hr>
  
  <p>I don't think it's relevant, but this is my code for configuring the navigation controller to perform interactive transitions:</p>
  
  <pre><code>- (void)viewDidLoad
  {
      [super viewDidLoad];
  
      self.navigationController.delegate = self;
  
      self.interationController = [[UIPercentDrivenInteractiveTransition alloc] init];
  }
  
  - (id&lt;UIViewControllerAnimatedTransitioning&gt;)navigationController:(UINavigationController *)navigationController
                                    animationControllerForOperation:(UINavigationControllerOperation)operation
                                                 fromViewController:(UIViewController*)fromVC
                                                   toViewController:(UIViewController*)toVC
  {
      if (operation == UINavigationControllerOperationPush)
          return [[PushAnimator alloc] init];
  
      return nil;
  }
  
  - (id &lt;UIViewControllerInteractiveTransitioning&gt;)navigationController:(UINavigationController*)navigationController
                            interactionControllerForAnimationController:(id &lt;UIViewControllerAnimatedTransitioning&gt;)animationController
  {
      return self.interationController;
  }
  </code></pre>
  
  <p>My <code>PushAnimator</code> is:</p>
  
  <pre><code>@implementation PushAnimator
  
  - (NSTimeInterval)transitionDuration:(id &lt;UIViewControllerContextTransitioning&gt;)transitionContext
  {
      return 5.0;
  }
  
  - (void)animateTransition:(id&lt;UIViewControllerContextTransitioning&gt;)transitionContext
  {
      UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
      UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
  
      [[transitionContext containerView] addSubview:toViewController.view];
      toViewController.view.frame = CGRectOffset(fromViewController.view.frame, fromViewController.view.frame.size.width, 0);;
  
      [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
          toViewController.view.frame = fromViewController.view.frame;
      } completion:^(BOOL finished) {
          [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
      }];
  }
  
  @end
  </code></pre>
  
  <p>Note, when I put logging statement where I call <code>completeTransition</code>, I can see that this extraneous bit of animation happens after I call <code>completeTransition</code> (even though the animation was really done at that point). This would suggest that that extra animation may have been a result of the call to <code>completeTransition</code>.</p>
  
  <p>FYI, I've done this experiment with a gesture recognizer:</p>
  
  <pre><code>- (void)handlePan:(UIScreenEdgePanGestureRecognizer *)gesture
  {
      CGFloat width = gesture.view.frame.size.width;
  
      if (gesture.state == UIGestureRecognizerStateBegan) {
          [self performSegueWithIdentifier:@"pushToSecond" sender:self];
      } else if (gesture.state == UIGestureRecognizerStateChanged) {
          CGPoint translation = [gesture translationInView:gesture.view];
          [self.interactionController updateInteractiveTransition:ABS(translation.x / width)];
      } else if (gesture.state == UIGestureRecognizerStateEnded ||
                 gesture.state == UIGestureRecognizerStateCancelled)
      {
          CGPoint translation = [gesture translationInView:gesture.view];
          CGPoint velocity    = [gesture velocityInView:gesture.view];
          CGFloat percent     = ABS(translation.x + velocity.x * 0.25 / width);
  
          if (percent &lt; 0.5 || gesture.state == UIGestureRecognizerStateCancelled) {
              [self.interactionController cancelInteractiveTransition];
          } else {
              [self.interactionController finishInteractiveTransition];
          }
      }
  }
  </code></pre>
  
  <p>I also did it by calling the <code>updateInteractiveTransition</code> and <code>finishInteractiveTransition</code> manually (eliminating the gesture recognizer from the equation), and it still exhibits this strange behavior:</p>
  
  <pre><code>[self performSegueWithIdentifier:@"pushToSecond" sender:self];
  
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
      [self.interactionController updateInteractiveTransition:0.40];
  
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
          [self.interactionController finishInteractiveTransition];
      });
  });
  </code></pre>
  
  <p>Bottom line, I've concluded that this is a problem isolated to <code>UIPercentDrivenInteractiveTransition</code> with complex animations. I can minimize the problem by simplifying them (e.g. snapshotting and animated snapshotted views). I also suspect I could solve this by not using <code>UIPercentDrivenInteractiveTransition</code> and writing my own interaction controller, which would do the animation itself, without trying to interpolate the <code>animationWithDuration</code> block. </p>
  
  <p>But I was wondering if anyone has figured out any other tricks to using <code>UIPercentDrivenInteractiveTransition</code> with complex animations. </p>