title: Calling layoutIfNeeded inside UIView animation block cause subviews to move earlier
body: <p>I'm trying to create a custom callout bubble.
  I have an animation block setting the scale transform of the bubble UIView:</p>
  
  <pre><code>self.view.transform = CGAffineTransformMakeScale(0, 0); // (1)
  self.view.transform = CGAffineTransformIdentity; // (2)
  </code></pre>
  
  <p>I either start the bubble view with scale (0, 0) as in (1) and animate to Identity as in (2) inside the animation block, or the opposite, going from (2) to (1).</p>
  
  <p>If I don't have the <code>[self.view layoutIfNeeded];</code> in my animation block, going from (1) to (2) works fine as in:</p>
  
  <p><img src="https://i.stack.imgur.com/QBE6e.png" alt="enter image description here"></p>
  
  <p>But when going back from (2) to (1) without the <code>[self.view layoutIfNeeded];</code>, the subviews jump to the left before the animation is finished:</p>
  
  <p><img src="https://i.stack.imgur.com/ZSNGO.png" alt="enter image description here"></p>
  
  <p>Now, if I do add the <code>[self.view layoutIfNeeded];</code> the subviews animate with the bubble view, but with a sort of delay:</p>
  
  <p>Either going from (1) to (2):</p>
  
  <p><img src="https://i.stack.imgur.com/ooD8A.png" alt="enter image description here"></p>
  
  <p>Or from (2) to (1):</p>
  
  <p><img src="https://i.stack.imgur.com/eIYqV.png" alt="enter image description here"></p>
  
  <p>I have already tried replacing all the top and leading subview's constraints with center constraints like in <a href="https://stackoverflow.com/questions/12943107/how-do-i-adjust-the-anchor-point-of-a-calayer-when-auto-layout-is-being-used">How do I adjust the anchor point of a CALayer, when Auto Layout is being used?</a> and have also tried the layer transform solution (but this one breaks the layout constraints saying it can't satisfy all constraints).</p>
  
  <p>Any ideas on how to solve my animation problem?</p>
  
  <p>Thanks in advance.</p>
  
  <p><strong>UPDATE:</strong>
  I'm updating the question with the actual method that I call on</p>
  
  <pre><code>- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)annotationView
  </code></pre>
  
  <p>and</p>
  
  <pre><code>- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)annotationView
  </code></pre>
  
  <p>to present and dismiss my custom callout bubble (forget the Expanded state for now).</p>
  
  <pre><code>- (void)setCalloutState:(CalloutState)calloutState
                 animated:(BOOL)animated
           annotationView:(MKAnnotationView *)annotationView
               completion:(void (^)(BOOL finished))completion
  {
      if (self.view.superview == annotationView || !annotationView) {
  
      } else {
  //        [self.view.layer removeAllAnimations];
          [self.view removeFromSuperview];
  
          self.view.transform = CGAffineTransformIdentity;
          self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
          self.view.transform = CGAffineTransformMakeScale(0, 0);
          self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);
  
          [annotationView addSubview:self.view];
      }
  
      void (^animationBlock)(void) = ^{
          self.view.transform = CGAffineTransformIdentity;
  
          switch (calloutState) {
              case CalloutStateHidden:
                  self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
                  self.view.transform = CGAffineTransformMakeScale(0, 0);
                  break;
              case CalloutStateNormal:
                  self.view.bounds = CGRectMake(0, 0, normalViewWidth, normalViewHeight);
                  break;
              case CalloutStateExpanded:
                  self.view.bounds = CGRectMake(0, 0, expandedViewWidth, expandedViewHeight);
                  break;
              default:
                  break;
          }
  
          self.view.center = CGPointMake(annotationView.bounds.size.width / 2, 0);
  
          [self.view layoutIfNeeded];
      };
  
      if (animated) {
          // TODO: figure out why the first animateWithDuration is needed in this nested thing
          [UIView animateWithDuration:0
                                delay:0
                              options:UIViewAnimationOptionBeginFromCurrentState
                           animations:NULL
                           completion:^(BOOL finished) {
  
                               [UIView animateWithDuration:1.3
                                                     delay:0
                                                   options:UIViewAnimationOptionBeginFromCurrentState
                                                animations:animationBlock
                                                completion:^(BOOL finished) {
                                                    if (finished) {
                                                        self.calloutState = calloutState;
  
                                                        // TODO: figure out how to end UIView animation instantly so we don't need the second condition at the if
                                                        // having a concurrency problem here
                                                        if (calloutState == CalloutStateHidden &amp;&amp; self.view.superview == annotationView) {
                                                            [self.view removeFromSuperview];
                                                        }
  
                                                        self.editingEnabled = calloutState == CalloutStateExpanded;
                                                    }
  
                                                    if (completion) {
                                                        completion(finished);
                                                    }
                                                }];
  
                           }];
          // ---------------------------------------------------------------------------------
      } else {
          animationBlock();
  
          self.calloutState = calloutState;
          if (calloutState == CalloutStateHidden) {
              [self.view removeFromSuperview];
          }
  
          self.editingEnabled = calloutState == CalloutStateExpanded;
  
          if (completion) {
              completion(YES);
          }
      }
  }
  </code></pre>