CALayer 从当前值淡出

Posted

技术标签:

【中文标题】CALayer 从当前值淡出【英文标题】:CALayer fade from current value 【发布时间】:2012-04-18 21:56:54 【问题描述】:

我的应用使用CALayer 来绘制视图。更准确地说,它在UIView 的顶层的子层上使用​​drawLayer:inContext: 方法。这是让连续drawLayer:inContext: 绘图的“隐式”动画随着时间的推移逐渐淡入彼此的好方法。渐变动画发生得相当快,可能在 0.25 秒内,但要更改其持续时间,只需实现另一个名为 actionForLayer:forKey: 的委托方法。在这个完美运行的示例实现中,默认持续时间延长到 2.0 秒:

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:event];
    animation.duration = 2.0;
    return animation;

    // or return nil for the default duration.

关于手头的问题。

如果您调用[sublayer setNeedsDisplay] 的速度快于淡入淡出完成的时间,那么每次新的淡入淡出您都会看到突然跳跃。从外观上看,正在进行的淡入淡出被取消,其最终状态被用作新淡入淡出的起点。这可能不是很令人惊讶,但视觉效果是相当不受欢迎的。

考虑从黑色到白色的 10 秒渐变,然后在开始 5 秒后触发另一个渐变到黑色的场景。动画将开始从黑色渐变为白色,但当它处于“半灰色”时,它会跳到全白,然后再次渐变为黑色。

有没有办法防止这种情况发生?我可以让图层从灰色变回黑色吗?有没有相当于 UIViewAnimationOptionBeginFromCurrentState 的 CALayer 绘图(用于 UIView 动画)?

干杯。

【问题讨论】:

【参考方案1】:

层的动画只是层在动画时应该是什么样子的视觉表示。在 CA 中,当您从一种状态动画到另一种状态时,图层的整个状态会立即更改。创建一个表示层并显示动画,当动画完成时,实际层留在最后。

所以,我的猜测是,当你想从一种状态过渡到另一种状态,而当前动画还没有完成时,你必须捕获动画的当前状态,然后使用这是您下一个动画的起点。

问题在于无法修改图层的当前动画。

在下面的文章中,我捕获了动画的当前状态,将其设置为图层的当前状态,并将其用作动画的起始值。该帖子将此技术应用于动画的速度/持续时间,但也可以应用于您的场景。

https://***.com/a/9544674/1218605

【讨论】:

P.S.这篇文章帮助我找到了我正在开发的 API 中的一个错误......谢谢。【参考方案2】:

我也对这个有点难过。

您是否忘记指定填充模式kCAFillModeForwards。有更多关于 in the reference docs 的信息。

例如,虽然我没有更改持续时间,但我让它在没有任何捕捉的情况下工作。

@implementation FadingLayer

- (void)fadeOut     
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
    animation.fillMode = kCAFillModeForwards;
    animation.fromValue = (id)[UIColor redColor].CGColor;
    animation.toValue = (id)[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.0].CGColor;
    animation.removedOnCompletion = FALSE;
    animation.delegate = self;    
    [self addAnimation:animation
                    forKey:@"test"];


- (void)fadeIn 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
    animation.fillMode = kCAFillModeForwards;
    animation.fromValue = (id)[UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.0].CGColor;
    animation.toValue = (id)[UIColor redColor].CGColor;
    animation.removedOnCompletion = FALSE;
    animation.delegate = self;    
    [self addAnimation:animation
                    forKey:@"test"];


@end

不过,您可能想要为 a custom property 制作动画。

希望这会有所帮助:/

【讨论】:

因为我使用的是drawLayer:inContext:,其中的淡入淡出是隐式动画的,所以设置 kCAFillModeForwards 属性没有帮助。感谢您的尝试!【参考方案3】:

我想用层树的缩放动画来完成同样的事情。我有一个放大/缩小键等效项,用户可以相应地缩放图层树。但是,如果用户快速连续按下等效的缩放键,则会暂时恢复到动画开始之前的值,因为之前的动画尚未完成。

在动画代码的最后,执行一个单一的[CATransaction commit] 强制所有未决事务在下一个动画开始之前提交到层模型,并解决了问题。

文档说:

+ 提交

提交当前事务期间所做的所有更改。

声明

+(无效)提交

特别注意事项

如果当前不存在事务,则引发异常。

但是,连续使用许多[CATransaction commit] 消息对此进行测试实际上并不会引发异常。我使用了同样的技术来消除表单的警告:

CoreAnimation:警告,删除未提交的线程 CATransaction;

在 NSOperation 中,其执行线程在层动画之前完成。如果当前不存在交易,Apple 可能会在最近的操作系统版本中将此行为更改为无操作(这会更明智),而不更新文档。

【讨论】:

以上是关于CALayer 从当前值淡出的主要内容,如果未能解决你的问题,请参考以下文章

修复 UIScrollView 顶部和底部的 CALayer

CALayer 帧值即使在从超级层中移除后也会导致动画

淡出 UIView?

位于关键帧值中间的 CALayer 的 CAKeyframeAnimation?

动画期间无法获取 CALayer 的当前位置

带有 CATransaction 的 CALayer 动画在视图调整大小之前表现不同