不带动画更改CAShapeLayer

17

我想设置一个CAShapeLayerstrokeEnd属性,但不希望出现默认动画,也不需要任何动画效果。我搜索了一下,但似乎所有的内容都是关于如何动画属性。

3个回答

46
在核心动画术语中,动画的更一般术语是“操作”(action)。例如,您可以看到CAAnimation符合CAAction协议。当禁用它们(禁用动画)时,您还会看到术语“操作”被使用。
有许多不同的方法可以更改图层的操作。其中许多在CALayer上的actionForKey:文档中记录得非常好(下面是摘录)。其中一些在子类化时更相关(您还可以在子类中覆盖actionForKey:以添加更多新键的隐式操作)。

此方法按以下顺序搜索图层的关联操作:

  1. 如果该图层具有委托并且该委托实现了访问图层滤镜的方法,则该图层调用该方法。委托必须执行以下操作之一:
    • 返回给定键的操作对象。
    • 如果它不处理操作,则返回nil
    • 如果它不处理操作并且搜索应终止,则返回NSNull对象。
  2. 图层查看图层的actions字典。
  3. 图层在样式字典中查找包含该键的操作字典。
  4. 图层调用其defaultActionForKey:方法以查找任何类定义的操作。
  5. 图层查找由核心动画定义的任何隐式操作。

当您想要禁用动画时,最有趣的两种方法是(它们不同,因为它们用于略微不同的事情):

  1. 使用CATransaction禁用操作(上面未提到)
  2. 在操作字典中为@"strokeEnd"键设置[NSNull null](上面的第2个数字)

禁用操作

使用事务来禁用动画很好,因为您希望在完全禁用多个属性的操作的同时仍然在其他所有位置进行动画。在代码中,它看起来像这样:

[CATransaction begin];
[CATransaction setDisableActions:YES];
// change your property here 
yourShapeLayer.strokeEnd = 0.7;
[CATransaction commit]; // animations are disabled until here...

更改动作字典

通过修改图层的操作字典,您可以永久更改一个或多个关键帧的默认动画。将[NSNull null]设置为意味着不应有动画,并且该层应停止在其他地方寻找默认动画。您还可以使用此方法添加可动画属性。通过操作字典删除动画的示例代码如下:

yourShapeLayer.actions = @{@"strokeEnd": [NSNull null]};
yourShapeLayer.strokeEnd = 0.7; // this won't have an animation

喜欢这个答案,但它引发了更多的问题。所以这里有两个问题:(1)如何在显式事务范围内禁用所有图层和所有键的动画变化,以及(2)如何永久禁用指定图层和键的动画。但是,如何仅针对一个更改禁用指定图层和键的动画? - algal
@algal 是的,有时候我似乎会写长篇回答 :) 我会说,如果只是一次性的事情,那么事务是最简单的。如果你只想将其应用于一个特定的图层和一个属性,那么只需在事务范围内更改该图层上的该属性即可。 - David Rönnqvist

2
您可以按照以下方式进行操作:
NSDictionary *actions = @{@"strokeEnd": [NSNull null]};
yourShapeLayer.actions = actions;

这将使该属性不进行动画效果。您还可以通过将其他属性添加到其中来指定不进行动画的附加属性:
NSDictionary *actions = @{@"strokeEnd": [NSNull null], @"position": [NSNull null], @"position": [NSNull null]};

0
我认为一个好的解决方案是创建一个CABasicAnimation(keyPath: "strokeEnd")并将持续时间设置为非常小的值。以下是一个示例:
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
basicAnimation.toValue = someValue
basicAnimation.duration = animated ? 2.0 : 0.01
basicAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

basicAnimation.fillMode = kCAFillModeForwards
basicAnimation.isRemovedOnCompletion = false

// Apply the animation
circleProgress.add(basicAnimation, forKey: "progress")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接