我有一个名为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没有反映我设置的不透明度值?这是一个错误吗?
我做错了什么?
答案 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
设置为你想要的任何内容,因为动画将优先。仅在移除动画时(默认情况下在动画完成时才会发生),将再次使用该属性的模型值。