Why is my CATransaction not following the duration I set?

I am porting an iPhone application on Mac OS X. This code has been used successfully on an iPhone:

- (void) moveTiles:(NSArray*)tilesToMove { [UIView beginAnimations:@"tileMovement" context:nil]; [UIView setAnimationDuration:0.1]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(tilesStoppedMoving:finished:context:)]; for( NSNumber* aNumber in tilesToMove ) { int tileNumber = [aNumber intValue]; UIView* aView = [self viewWithTag:tileNumber]; aView.frame = [self makeRectForTile:tileNumber]; } [UIView commitAnimations]; } 

The Mac version uses CATransaction to group animations, for example:

 - (void) moveTiles:(NSArray*)tilesToMove { [CATransaction begin]; [CATransaction setAnimationDuration:0.1]; [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; [CATransaction setCompletionBlock:^{ [gameDelegate tilesMoved]; }]; for( NSNumber* aNumber in tilesToMove ) { int tileNumber = [aNumber intValue]; NSView* aView = [self viewWithTag:tileNumber]; [[aView animator] setFrame:[self makeRectForTile:tileNumber]]; } [CATransaction commit]; } 

The animation is excellent, except that the duration is 1.0 seconds. I can change setAnimationDuration: to call something or completely lower it, and the animation lasts 1.0 seconds. I also don't think that setAnimationTimingFunction: call does anything. However, setCompletionBlock: works because this block is executed when the animation completes.

What am I doing wrong here?

+4
source share
2 answers

If I'm not mistaken, you cannot directly use CoreAnimation to directly animate NSView. To do this, you need an NSAnimationContext and [NSView animator]. CATransaction will only work with CALayers.

+5
source

It doesn't exactly answer the question, but in the end I used NSAnimationContext instead of CATransaction.

 - (void) moveTiles:(NSArray*)tilesToMove { [NSAnimationContext beginGrouping]; [[NSAnimationContext currentContext] setDuration:0.1f]; for( NSNumber* aNumber in tilesToMove ) { int tileNumber = [aNumber intValue]; NSView* aView = [self viewWithTag:tileNumber]; [[aView animator] setFrame:[self makeRectForTile:tileNumber]]; CAAnimation *animation = [aView animationForKey:@"frameOrigin"]; animation.delegate = self; } [NSAnimationContext endGrouping]; } 

It works, but I'm not very happy with it. Basically, the NSAnimationContext does not have a callback completion mechanism such as CATransaction, so I had to put a thing in there to explicitly get the view animation and set a delegate to call the callback. The problem is that it runs several times for each animation. This, it turns out, has no harmful consequences for what I do, it is simply wrong.

It works, but if someone knows a better solution, I will still like it.

+2
source

All Articles