I have an class "Cube" and in there is a method -rotate. The method sets the anchorPoint at the bottom left and then rotates the cube by 90 degrees. After that, another method is called, which makes the cube to rotate back by -90 degrees. That's done specifying the stop selector. Btw: This has no special purpose. Just learning!
-rotate gets called upon an touch event. But now, when the cube object is still rotating, and let's say it's currently at 33.943..., the user might make another touch event before that animation has finished.
This touch event would then immediately invoke again the -rotate method. What happens is, that the transformations overlap and the cube image gets stretched and deformed totally.
So before the new animation begins, the currently running animation has to stop.
UPDATE
I call this, before I kick off the animation:
- (void)resetAnimation {
self.layer.transform = CATransform3DIdentity; // reset the transform to the identity transform ("no rotation applied, please")
[Cube setAnimationDelegate:nil];
[Cube setAnimationDidStopSelector:NULL];
}
Also, I set [Cube setAnimationBeginsFromCurrentState:YES]; everywhere where I begin an animation block.
So, when an animation is inited from the outside, this will look like this: (Note, that there are 5 objects of this class on the screen, which can be kicked to animate)
- (void)kickAnimation { // if that's called, the cube gets a kick to rotate
self.layer.transform = CATransform3DIdentity;
currentDegrees = 90; // just testing! it may also be negative
NSString *animID = [NSString stringWithFormat:@"cube_%i",self.datasetID];
if (currentDegrees > 0) {
[self rotateRight:animID finished:0 context:self];
} else if (currentDegrees < 0) {
[self rotateLeft:animID finished:0 context:self];
}
}
- (void)rotateRight:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
// 1) here the anchorPoint is set to the lower right corner
// 2) here the view's frame is repositioned so that the cube doesn't move visually after the anchorPoint changed
[self rotateByDegrees:currentDegrees animationID:animationID];
}
- (void)rotateByDegrees:(CGFloat)degrees animationID:(NSString *)animationID {
[Cube beginAnimations:animationID context:self];
[Cube setAnimationDelegate:self];
[Cube setAnimationDidStopSelector:@selector(rotateBack:finished:context:)];
[Cube setAnimationDuration:2.1f];
[Cube setAnimationBeginsFromCurrentState:YES];
CATransform3D rotatedTransform = self.layer.transform;
rotatedTransform = CATransform3DRotate(rotatedTransform, degrees * M_PI / 180.0, 0.0f, 0.0f, 1.0f);
self.layer.transform = rotatedTransform;
[UIView commitAnimations];
}
- (void)rotateBack:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
currentDegrees *= -1;
[Cube beginAnimations:animationID context:self];
self.layer.transform = CATransform3DIdentity;
[Cube setAnimationDelegate:nil];
[Cube setAnimationDidStopSelector:NULL];
[Cube setAnimationDuration:2.1f];
[Cube setAnimationBeginsFromCurrentState:YES];
CATransform3D rotatedTransform = self.layer.transform;
rotatedTransform = CATransform3DRotate(rotatedTransform, currentDegrees * M_PI / 180.0, 0.0f, 0.0f, 1.0f);
self.layer.transform = rotatedTransform;
currentDegrees = 0;
[UIView commitAnimations];
}
Now it seems to almost work. The cube doesn't deform anymore if animation-kickoffs overlap. But one thing stil is wrong: If an new "kick" comes in, and the cube is currently rotating back, it should imediately start rotating to right. But it happens that it first rotates back and then recognizes that "kick", which looks pretty queer ;)