48

I'm trying to execute a completion-block after my CAAnimation has finished. However, it seems that animation block is called before my animation completes. The animation still happens correctly though.

[CATransaction begin];
[self.view.layer addAnimation:self.dropAndBounceAnimation forKey:@"appearance"];
[CATransaction setCompletionBlock:completionBlock];
[CATransaction commit];

The dropAndBounceAnimation is a CAKeyFrameAnimation on position.y, with a fixed duration.

Javache
  • 3,307
  • 3
  • 18
  • 25

4 Answers4

111

I'm not sure if this really is the correct fix, but by setting the completion-block before adding the animation for the layer, the completion-block is consistently called at the correct time.

[CATransaction begin];
[CATransaction setCompletionBlock:completionBlock];
[self.view.layer addAnimation:self.dropAndBounceAnimation forKey:@"appearance"];
[CATransaction commit];
Javache
  • 3,307
  • 3
  • 18
  • 25
  • 20
    Yes it is, as per the [documentation](https://developer.apple.com/library/Mac/DOCUMENTATION/GraphicsImaging/Reference/CATransaction_class/Introduction/Introduction.html#//apple_ref/occ/clm/CATransaction/setCompletionBlock:): "The completion block object that is guaranteed to be called (on the main thread) as soon as all animations *subsequently added* by this transaction group have completed (or have been removed.)". The key part is "subsequently added". – albertamg Nov 14 '13 at 11:10
  • 2
    @albertamg However, it also states `If no animations are added before the current transaction group is committed (or the completion block is set to a different value,) the block will be invoked immediately.` – iwasrobbed Feb 14 '14 at 14:42
  • 1
    @iWasRobbed yes, and that explains why the block is called before the animation completes if it is set after adding the animation to the transaction group. – albertamg Feb 17 '14 at 10:41
  • also called immediately if you forgot to set `view.wantsLayer = YES;` – codrut Oct 27 '17 at 12:11
13

You need to set the completion block before adding the animation.

[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat: 1.0f] forKey:kCATransactionAnimationDuration];

[CATransaction setCompletionBlock:^{
// ... whatever you want to do when the animation is complete
}];

[self.googleMapsView animateToCameraPosition:[GMSCameraPosition 
                    cameraWithLatitude:LATITUDE
                             longitude:LONGITUDE
                                  zoom:ZOOM]];

[CATransaction commit];

This must trigger the completion block after the completion of that animation on the view.

Fattie
  • 30,632
  • 54
  • 336
  • 607
Saru
  • 833
  • 1
  • 14
  • 22
6

Here is Swift 3.0.1, Xcode 8 version:

CATransaction.begin()

CATransaction.setCompletionBlock({
  print("Transaction completed")
})

print("Transaction started")
view.layer.add(dropAndBounceAnimation, forKey: "appearance")

CATransaction.commit()
Vadim Bulavin
  • 2,991
  • 21
  • 17
0

Try to start the animation asynchronously:

DispatchQueue.main.async {
    self.startAnimation()
}

because it can interfere with view drawing if you make some view setup before calling the animation.

mixel
  • 22,724
  • 10
  • 111
  • 154