开发者

Remove Interpolation of CALayer's contents property

开发者 https://www.devze.com 2023-01-28 04:26 出处:网络
Re-asking the question: When you add an animation for the contents key, a CATransitionAnimation is apparently being triggered that fades the original contents property to the first value in the anima

Re-asking the question:

When you add an animation for the contents key, a CATransitionAnimation is apparently being triggered that fades the original contents property to the first value in the animation's values array, resulting in a .25 second fade. And it looks bad! I have suppressed every开发者_开发技巧 animatable property using all the methods discussed here (returning null animations through a delegate, into the actions dictionary, using CATransaction), but none of these seem to be targeting this particular transition animation.

Remove Interpolation of CALayer's contents property

I have been looking into what property could possibly be responsible for this, but cannot figure it out.

I need to suppress the transition animation that is occurring when you add an animation to the contents key.

As I'm at such a loss, I will put the keyframe animation that is being added for you to see. I figure maybe I am doing something wrong here? Just a note, that array is just an array of 6 CGImageRefs (the frames of the animation).

+ (CAKeyframeAnimation *)moveLeftAnimation {

CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
animation.values = [NSArray arrayWithArray:[Setzer walkingLeftSprite]];
animation.duration = 0.5f;
animation.keyTimes = [NSArray arrayWithObjects:
                      [NSNumber numberWithFloat:0.0], 
                      [NSNumber numberWithFloat:0.2], 
                      [NSNumber numberWithFloat:0.4],
                      [NSNumber numberWithFloat:0.6],
                      [NSNumber numberWithFloat:0.8],
                      [NSNumber numberWithFloat:1.0],
                      nil];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
return animation;

}

Also, I have an animation that handles the position key, in the sprite's action dictionary:

+ (CABasicAnimation *)moveAnimation {

CABasicAnimation *moveAnimation = [CABasicAnimation animation];
moveAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
moveAnimation.duration = 0.5f;

return moveAnimation;

}

I am thinking maybe this transition is occurring when you change the layer's position? I don't know...

Please help! This is driving me NUTS!


You can do something along the lines of what I describe in this answer, where I disable the implicit animations for various layer properties by setting the appropriate values in the actions dictionary on that layer.

In your case, I believe something like

NSMutableDictionary *newActions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
                                   [NSNull null], @"contents",
                                   nil];
layer.actions = newActions;
[newActions release];

should prevent the implicit animation of a layer's contents property until you explicitly animate it.


To prevent any animation, you could set an object as the delegate of your CALayer and then implement the ‑actionForLayer:forKey: delegate method and return a null object:

- (id<CAAction>)actionForLayer:(CALayer*)layer forKey:(NSString*)key 
{
    if(layer == yourLayer)
    {
        if([key isEqualToString:@"contents"])
        {
            return (id<CAAction>)[NSNull null];
        }
    }
    return nil;
}


Here are a few notes on how this puzzle was solved, and how everyone's answers provided a piece of the puzzle.

To restate the problem: when I added a keyframe animation to the @contents key of a CALayer, there appeared to be a .25 second fade transition between the original contents property and the first frame of the keyframe animation. This looked bad, and I wanted to get rid of it.

At first, I thought surely that by using a CATransaction I could suppress this implicit transition animation, as that is what Apple's docs lead you to believe. Using a transaction, I suppressed in every possible way you could imagine, and yet it was still happening. Then I tried returning NULL animations for every animatable property via a dictionary. No luck. Then I did the same thing, but with a delegate. Still no luck.

What I didn't mention is that at the same time the animation was being added and the layer was being moved, two sublayers beneath it were being removed from the their superlayers. I tried adding custom animations for the onOrderOut key, but to no avail. Then I stumbled upon another question here on StackOverflow, about adding a custom animation for the onOrderOut key. It turns out, quite simply, that you can't, and that if you wan to implement some other animation for when a sublayer is removed, you have to use the delagate method animationDidStop. How can I use custom animations for onOrderOut in Core Animation?

So at this point I was convinced that this ghost image had nothing to do with the actual layer in question, the sprite itself. To test this, I just didn't add the sublayers that went beneath it. Sure enough, there was no lingering ghost when I moved the sprite around. It looked perfect. Then I added the layers beneath there was the ghost. It was almost like the sprite's contents were drawn into the layers beneath it, so that when they were removed, there was a sort of imprint.

Instead of removing the sublayers, I just tried hiding them. Bingo. It was perfect. The same fade transition occurred, but there was no imprint of the sprite left. I still don't understand why this is so.

Then, because I still needed to remove those layers, I implemented the animationDidStop delegate method for the sprite's various movement animations to remove them.

This is the original:

Remove Interpolation of CALayer's contents property

This is the new version:

Remove Interpolation of CALayer's contents property

So while I don't understand, technically, why there appears to be an imprint, I am all but certain that it concerns what goes on behind the scenes when you remove a sublayer. Also, for interest sake, I still wanted that sublayer to be hidden on animation start, so I just set it to hidden and provided my own transition animation.

So thanks to everyone for their help. This is a strange use case, I know, but if you are ever thinking of making a 2d sprites-based Final Fantasy Tactics ripoff, then hopefully my pain will be to your benefit!


class AnimationLayer: CALayer {
    override class func defaultAction(forKey event: String) -> CAAction? {
        let transition = CATransition()
        transition.duration = 0
        return transition
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消