为什么我不能在CABasicAnimation完成后设置图层的不透明度?

时间:2012-09-13 19:29:57

标签: iphone ios ipad core-animation calayer

我有一个名为specialLayer的子图层。不透明度的隐式动画将被禁用,如下所示:

self.specialLayer.actions = [NSDictionary dictionaryWithObjectsAndKeys:
                                            [NSNull null], @"opacity", nil];

只有两种方法可以访问此子图层。

- (void)touchDown {
    self.specialLayer.opacity = 0.25f;
}

- (void)touchUp {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.fromValue = [NSNumber numberWithFloat:self.specialLayer.opacity];
    animation.toValue = [NSNumber numberWithFloat:1.0];
    animation.duration = 0.5;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    [self.specialLayer addAnimation:animation forKey:@"opacity"];
}

发生这种情况:

1)用户按下按钮(保持)并调用-touchDown。 specialLayer的不透明度立即变为0.25

2)用户释放按钮和-touchUp被调用。 specialLayer的不透明度动画回到1.0

此序列仅适用于ONCE!

3)用户再次按下按钮(按住)并调用-touchDown。但specialLayer的不透明度在屏幕上不会改变!即使调用self.specialLayer.opacity = 0.25f;也没有任何反应。不透明度似乎仍为1.0f。

4)用户抬起手指并调用-touchUp。 specialLayer的不透明度为0.25,从那里动画到1.0f。

我检查了NSLog以确保按此顺序调用方法。他们这样做。

当我取消注释动画代码并将不透明度直接设置为1.0时,后续的直接不透明度更改会立即生效。绝对是导致问题的CABasicAnimation。删除禁用隐式动画的代码对此问题没有影响。

我不能为我的生活弄清楚这里发生了什么。为什么在我为不透明度添加CABasicAnimation之后的一段时间后,CALayer没有反映我设置的不透明度值?这是一个错误吗?

我做错了什么?

1 个答案:

答案 0 :(得分:8)

您将动画的removedOnCompletion设置为NO。这意味着当动画完成时,它仍然停留在图层上,并且仍然为了渲染的目的控制opacity的值。当您第二次调用此代码时,新动画将替换旧动画,这会导致跳转(因为它现在使用新设置的0.25f作为起点)。

解决方案是停止将removedOnCompletion设置为NO。相反,您应该在添加动画的同时,将图层的实际不透明度设置为与动画端点相同的值。

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
// you can omit fromValue since you're setting it to the layer's opacity
// by omitting fromValue, it uses the current value instead. Just remember
// to not change layer.opacity until after you add the animation to the layer
animation.toValue = [NSNumber numberWithFloat:1];
animation.duration = 0.5;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[layer addAnimation:animation forKey:@"opacity"];
layer.opacity = 1; // or layer.opacity = [animation.toValue floatValue];

这是因为图层渲染的工作方式。当CoreAnimation将图层树渲染到屏幕时,它会复制模型树并生成所谓的表示树。它通过复制所有图层,然后应用所有动画来完成此操作。因此,它会遍历图层上的每个动画,将时间插入计时功能,将生成的进度插入到from / to值之间的插值中,并将该最终值应用回表示层的属性。

因此,当您永久地在图层上留下动画时,此动画将始终覆盖该键的实际模型值。更改layer.opacity的次数无关紧要,控制opacity的动画将始终覆盖该值以用于演示目的。

同样的原因也是为什么你可以在添加动画后将layer.opacity设置为你想要的任何内容,因为动画将优先。仅在移除动画时(默认情况下在动画完成时才会发生),将再次使用该属性的模型值。