The scope of a CATransaction block

2019-06-14 05:51发布

问题:

I have seen some code that removes a given layer from it's superlayer by doing the following:

void RemoveImmediately(CALayer *layer) {
    [CATransaction flush];
    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue
                     forKey:kCATransactionDisableActions];
    [layer removeFromSuperlayer];
    [CATransaction commit];
}  

I have written a method that changes the position of a given layer in an animated way using CAKeyframeAnimation, which looks like this:

- (void)animateMovingObject:(NXUIObject*)obj
           fromPosition:(CGPoint)startPosition
             toPosition:(CGPoint)endPosition
               duration:(NSTimeInterval)duration {    

    CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    pathAnimation.calculationMode = kCAAnimationPaced;
    pathAnimation.duration = duration;

    CGMutablePathRef curvedPath = CGPathCreateMutable();
    CGPathMoveToPoint(curvedPath, NULL, startPosition.x, startPosition.y);
    CGPathAddCurveToPoint(curvedPath, NULL, 
                      startPosition.x, endPosition.y, 
                      startPosition.x, endPosition.y,
                      endPosition.x, endPosition.y);
    pathAnimation.path = curvedPath;
    [obj addAnimation:pathAnimation forKey:@"pathAnimation"];
    CGPathRelease(curvedPath);
}

Up to know, everything is fine. Now suppose I have in my app a 'master layer', which has 3 sublayers. I want the first two sublayers to be moved to another position and the last one to be removed. So I did the following:

CALayer obj1 = ... // set up layer and add as sublayer
[self.masterLayer addSublayer:obj1];
[self animateMovingObject:obj1
             fromPosition:CGPointMake(0.0, 0.0)
               toPosition:CGPointMake(100.0, 100.0)
                 duration:2.0];

CALayer obj2 = ... // set up layer and add as sublayer
[self.masterLayer addSublayer:obj2];
[self animateMovingObject:obj2
             fromPosition:CGPointMake(0.0, 0.0)
               toPosition:CGPointMake(150.0, 100.0)
                 duration:2.0];

CALayer obj3 = ... // set up layer and add as sublayer
[self.masterLayer addSublayer:obj3];
// ...
RemoveImmediately(obj3);      // This removes the two previous animations too
//[obj3 removeFromSuperlayer];  // This just removes obj3, the previous animations works

Note that if I call RemoveImmediately(), even passing obj3 as argument I can't see the first two layers being animated. However, if I remove the obj3 just by calling removeFromSuperlayer the first two layers are animated normally. Looks like the CATransaction block cancels all animations being done, even those that were created with CAKeyframeAnimation.

What I'm I missing?

Thanks In advance.

回答1:

The scope of a CATransaction should just be between the [CATransaction begin] and [CATransaction commit] lines.

Also, you shouldn't need the [CATransaction flush] in that code. Apple generally recommends you not force the execution of pending transactions for performance reasons, and the transaction you're setting up there should not affect any pending animations.

I'm guessing this odd behavior is still related to what you asked in your previous question, where the three animations are somehow interfering with one another. As I commented there, this is behaving like the three animations are being added to one layer, not three independent ones. I'd check and make sure there was no possibility of that happening (crossed pointers, etc.).