选择性地覆盖 CALayer 隐式动画

Posted

技术标签:

【中文标题】选择性地覆盖 CALayer 隐式动画【英文标题】:Selectively overriding CALayer implicit animations 【发布时间】:2011-04-08 00:51:27 【问题描述】:

我有一个 CALayer 子类,它被限制为父层的宽度,但高度是固定的。我希望在调整窗口大小时禁用隐式动画,但在设置图层高度时启用。

要在调整窗口大小时禁用动画,我将图层操作设置为

NSMutableDictionary *actions = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNull null], @"bounds", [NSNull null], @"position", nil];

这似乎有效。然后我覆盖了层子类中的 actionForKey: 方法

- (id<CAAction>)actionForKey:(NSString *)event

    if ([event isEqualToString:@"frame.size.height"]) 
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"frame.size.height"];
        [animation setDuration:0.5f];
        return animation;
    
    return nil;

但是当我改变我的层的高度时

[layer setValue:[NSNumber numberForFloat:50.0] forKey:@"frame.size.height"];

高度改变但没有动画。我看到使用 frame.size.height 调用 actionForKey: 方法,但无论我返回什么,它都不会被动画化。如果我没有设置动作,或者没有 actionForKey: 方法,高度会正确动画,但是窗口大小也会被动画,这是我不想要的。

另外,也许我误解了,但我认为从 actionForKey: 返回 nil 会使默认动画运行,但似乎即使该方法的存在也会停止所有隐式动画(无论操作字典是否设置) .

我在这里缺少什么,我将不胜感激。

【问题讨论】:

【参考方案1】:

您的子类将为每个键调用actionForKey:,因此如果您返回nil,则不会对该键执行任何操作。如果你想要默认动画,你应该返回[super actionForKey:event][CALayer defaultActionForKey:event]

一个层的frame是从它的boundsposition计算出来的,所以如果这两个没有动画,frame就没有动画。*

你想做的是:

[CATransaction setValue:kCFBooleanTrue
                 forKey:kCATransactionDisableActions]

当您的图层因窗口大小调整而调整大小时。这将在这次禁用动画(对于此事务);当您直接更改图层的大小时,它仍然会动画。我不确定打那个电话的正确位置是什么;我只是尝试在通知窗口正在调整大小的回调中执行此操作,但这不起作用。我相信你不会很难弄清楚将它放在代码中的什么位置。


*:事实上,文档说:

注意:frame 属性不能直接设置动画。相反,您应该对 bounds、anchorPoint 和 position 属性的适当组合进行动画处理,以获得所需的结果。

【讨论】:

谢谢你,这一切都清楚了。我最终继承了 CAConstraintsLayoutManager 并禁用了 layoutSublayersOfLayer: 方法中的操作。它似乎有效,虽然我不知道这是否是最好的方法。 听起来不错。我让我的观点本身采用CALayoutManager 协议来处理一个相关的、稍微简单的案例。很高兴我能帮上忙。 如果你禁用父层的 layoutSublayers 方法中的操作,它似乎也可以工作。【参考方案2】:

有,正如他们所说.. 给这只猫剥皮的几种方法...我发现其中一种最容易...通过在图层的“动作”字典中设置一些条目。 .

CALayer *stopAnimatingLikeThat = CALayer.new;
stopAnimatingLikeThat.actions  =
  @ @"position":NSNull.null, @"bounds":NSNull.null ;

这将阻止边界变化等烦人的“卡在蜂蜜中”“隐式动画”等。

【讨论】:

这是一个很好的方法,因为您可以将 CALayer 设置为在初始化时不调整位置和边界的大小。 在没有隐式动画的图层中重绘文本yourLayer.actions = @ @"contents":NSNull.null ;

以上是关于选择性地覆盖 CALayer 隐式动画的主要内容,如果未能解决你的问题,请参考以下文章

通过 AVExportSession 导出带有隐式动画的 CALayer

CALayer“内容”属性上的隐式动画

隐式动画和核心动画

在 -[CALayer setNeedsDisplayInRect:] 中禁用隐式动画

为啥我替换了一个 CALayer 的位置隐式动画,它仍然在我自己的位置之前开始?

iOS边练边学--CALayer,非根层隐式动画,钟表练习