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

标签 iphone ios ipad core-animation calayer

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

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

这个序列只有效一次!

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

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

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

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

我这辈子都搞不清楚这里发生了什么。为什么 CALayer 不反射(reflect)我为不透明度添加 CABasicAnimation 后一段时间后设置的不透明度值?这是错误吗?

我做错了什么?

最佳答案

您将动画的 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 设置为任何你想要的,因为动画将优先。只有当动画被移除时(默认情况下发生在动画完成时)才会再次使用该属性的模型值。

关于iphone - 为什么我不能在 CABasicAnimation 完成后设置图层的不透明度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12413459/

相关文章:

iphone - 无法通过 UINavigationcontroller.viewControllers 更改类的属性

iphone - 如何使用 UITouch 移动铅笔图像?

ios - XMPPFramework - 如何注册新用户帐户

iphone - UIWebview中本地html文件加载

ios - 用于在 ios 应用程序中存储大量数据的 HTML 文件或核心数据

iphone - cocoa touch 如何: MPMoviePlayerController loop?

ios - 什么是 UITabBarItem *item = [self.tabBar.items objectAtIndex :1]; in swift?

ios - NSFetchedResultsController 更改跟踪

ios - 在我的 iPad 中下载的任一 pdf 应用程序中显示 pdf 文件

ios - 如何隐藏 UINavigationBar 1px 底线