如何在动画完成时删除图层?

时间:2013-07-16 23:06:54

标签: iphone ios animation calayer caanimation

我正在制作 iOS App 。我有几个CALayer个对象,最终将被<缩小的动画 删除。完成动画并调用animationDidStop:finished后,我想超级视图中删除 CALayer对象并将其删除。

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

4 个答案:

答案 0 :(得分:5)

回答这个问题已有很长时间了,但是,如果今天仍然有人在寻找更干净的解决方案,我将尝试添加更多的迅速解决方案。

如果您感兴趣的一切只是在CAAnimation完成后立即删除该层,则可以将动画的委托分配给一个简单的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 documentation中我们可以读取

  

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

答案 1 :(得分:1)

创建动画并设置委托时,只需使用动画传递要删除的CALayer。

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

  1. 您可以检查CALayer的animationKeys是否有任何现有动画。
  2. 您可以使用CAAnimationGroup并将所有动画组合在一起。

答案 2 :(得分:0)

看看这个答案是否有帮助:Perform an action after the animation has finished我发现animateWithDuration:动画:完成:比直接使用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
        }];
    }];
}];

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

答案 3 :(得分: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];