5

我正在制作一个iOS App。我有几个CALayer对象最终会被(缩小的)动画删除。当动画完成并被调用时,我想从超级视图中删除对象并将其删除。animationDidStop:finishedCALayer

  1. 但是我怎样才能得到CALayer对象 animationDidStop:finished呢?我会猜到 CAanimation-object 有一个指向图层的指针,但我在文档中找不到它。
  2. 有没有更好的方法来处理这个问题?(实际上,我有几个动画对象添加到同一层,理想情况下,我只想在最后一个动画完成时删除该层)
4

4 回答 4

9

这个问题已经很久没有回答了,但是我会尝试添加一个更快速的解决方案,以防现在有人仍在寻找更干净的解决方案。

如果您感兴趣的只是在 CAAnimation 完成后立即删除该层,您可以将动画的委托分配给一个简单的 NSObject,该 NSObject 包含对目标层的引用并等待动画回调以将其关闭。

让我们将此辅助对象称为 LayerRemover

class LayerRemover: NSObject, CAAnimationDelegate {
    private weak var layer: CALayer?

    init(for layer: CALayer) {
        self.layer = layer
        super.init()
    }

    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        layer?.removeFromSuperlayer()
    }
}

该对象所做的一切都是通过初始化程序接收 CALayer 引用,并在移除层之前等待 animationDidStop 回调。此时,一旦通过委托属性保留它的 CAAnimation 被取消初始化,Layer remover 也会被清除。

现在,您所要做的就是将这个卸妆器实际化并使用它:

let layer = CAShapeLayer()
layer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 200, height: 100)).cgPath
let myAnimation = CABasicAnimation(keyPath: "strokeEnd")
...
myAnimation.delegate = LayerRemover(for: layer)

而已!

请注意,您不必保留对 LayerRemover 对象的任何引用,因为我们可以从Apple 文档中了解到

委托对象由接收者保留。这是高级内存管理编程指南中描述的内存管理规则的罕见例外。

于 2018-06-20T12:40:24.483 回答
1

当您创建动画并设置委托时,只需将您想要删除的 CALayer 与动画一起传递。

至于删除所有动画,您有两个选择:

  1. 您可以检查您的 CALayer 的动画键是否存在任何现有动画。
  2. 您可以使用 CAAnimationGroup 并将所有动画组合在一起。
于 2013-07-16T23:20:49.047 回答
0

看看这个答案是否有帮助:在动画完成后执行一个动作 我发现 animateWithDuration:animations:completion: 比直接使用 CALayer 更容易使用。您可以通过完成处理程序链接多个动画,然后删除最后一个中的图层。例如:

[UIView animateWithDuration:1.0 animations:^{
    // do first animation in the sequence
} completion:^(BOOL finished) {
    [UIView animateWithDuration:1.0 animations:^{
        // do second animation in the sequence
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:1.0 animations:^{
            // do third animation in the sequence
        } completion:^(BOOL finished) {
            // remove layer after all are done
        }];
    }];
}];

这种方式可能有点混乱,但是您可以将它们重构为它们自己的方法调用,例如。

于 2013-07-16T23:19:47.763 回答
0

一种替代解决方案是向动画对象的字典添加层指针,如下所示

// in some define section
#define kAnimationRemoveLayer @"animationRemoveLayer"

然后,在animationDidStop中,

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
    CALayer *lay = [theAnimation valueForKey:kAnimationRemoveLayer];
    if(lay){
        [lay removeAllAnimations];
        [lay removeFromSuperlayer];
    }
}

最后,在动画设置中,

CALAyer * lay = ... ;
BOOL    shouldRemove = .... ; 
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"position"];
anim.delegate = self;
if (shouldRemove)
    [anim setValue:lay forKey:kAnimationRemoveLayer];
于 2013-08-08T16:53:43.897 回答