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

Pro*_*ber 2 iphone core-animation calayer ipad ios

我有一个名为sublayer的视图specialLayer.不透明度的隐式动画被禁用,如下所示:

self.specialLayer.actions = [NSDictionary dictionaryWithObjectsAndKeys:
                                            [NSNull null], @"opacity", nil];
Run Code Online (Sandbox Code Playgroud)

访问此子图层的方法只有两种.

- (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"];
}
Run Code Online (Sandbox Code Playgroud)

有时候是这样的:

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没有反映我设置的不透明度值?这是一个错误吗?

我究竟做错了什么?

Lil*_*ard 8

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

解决的办法是只停留设置removedOnCompletionNO.相反,您应该在添加动画的同时,将图层的实际不透明度设置为与动画端点相同的值.

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];
Run Code Online (Sandbox Code Playgroud)

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

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

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