CALayer的动画结束回调?

时间:2008-11-17 21:17:16

标签: iphone core-animation

我想知道CALayer中动画的回调位置(或者有什么内容)。具体来说,对于隐含的动画,如改变框架,位置等。在UIView中,你可以这样做:

[UIView beginAnimations:@"SlideOut" context:nil];
[UIView setAnimationDuration:.3];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animateOut:finished:context:)];
CGRect frame = self.frame;
frame.origin.y = 480;
self.frame = frame;
[UIView commitAnimations];

具体来说,setAnimationDidStopSelector是我想要的CALayer中的动画。有什么类似的吗?

TIA。

11 个答案:

答案 0 :(得分:119)

你可以使用CATransaction,它有一个完成块处理程序。

[CATransaction begin];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
[pathAnimation setDuration:1];
[pathAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];    
[pathAnimation setToValue:[NSNumber numberWithFloat:1.0f]];
[CATransaction setCompletionBlock:^{_lastPoint = _currentPoint; _currentPoint = CGPointMake(_lastPoint.x + _wormStepHorizontalValue, _wormStepVerticalValue);}];
[_pathLayer addAnimation:pathAnimation forKey:@"strokeEnd"];
[CATransaction commit];

答案 1 :(得分:56)

我回答了自己的问题。您必须使用CABasicAnimation添加动画,如下所示:

CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"frame"];
anim.fromValue = [NSValue valueWithCGRect:layer.frame];
anim.toValue = [NSValue valueWithCGRect:frame];
anim.delegate = self;
[layer addAnimation:anim forKey:@"frame"];

实现委托方法animationDidStop:finished:,你应该好好去。谢天谢地,这个功能存在! :d

答案 2 :(得分:49)

用这种垃圾浪费了4个小时,只是为了淡出淡出。 请注意代码中的注释。

   [CATransaction begin];
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    animation.duration = 0.3;
    animation.fromValue = [NSNumber numberWithFloat:0.0f];
    animation.toValue = [NSNumber numberWithFloat:1.0f];
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeBoth;
  ///  [box addAnimation:animation forKey:@"j"]; Animation will not work if added here. Need to add this only after the completion block.

    [CATransaction setCompletionBlock:^{

        CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"opacity"];
        animation2.duration = 0.3;
        animation2.beginTime = CACurrentMediaTime()+1;
        animation2.fromValue = [NSNumber numberWithFloat:1.0f];
        animation2.toValue = [NSNumber numberWithFloat:0.0f];
        animation2.removedOnCompletion = NO;
        animation2.fillMode = kCAFillModeBoth;
        [box addAnimation:animation2 forKey:@"k"];

    }];

    [box addAnimation:animation forKey:@"j"];

    [CATransaction commit];

答案 3 :(得分:44)

以下是基于bennythemink解决方案的Swift 3.0中的答案:

    // Begin the transaction
    CATransaction.begin()
    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.duration = duration //duration is the number of seconds
    animation.fromValue = 0
    animation.toValue = 1
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    circleLayer.strokeEnd = 1.0

    // Callback function
    CATransaction.setCompletionBlock { 
        print("end animation")
    }

    // Do the actual animation and commit the transaction
    circleLayer.add(animation, forKey: "animateCircle")
    CATransaction.commit() 

答案 4 :(得分:38)

2018年......

斯威夫特4。

使用.setCompletionBlock

在实践中,您需要[weak self],否则您通常会崩溃。

func animeExample() {

    CATransaction.begin()

    let a = CABasicAnimation(keyPath: "fillColor")
    a.fromValue, duration = ... etc etc

    CATransaction.setCompletionBlock{ [weak self] in
        self?.animeExample()
    }

    someLayer.add(a, forKey: nil)
    CATransaction.commit()
}

在示例中,它只是再次调用自己。

当然,您可以调用任何函数。

注意:如果您刚开始使用。值得记住的是

  1. " key" (如在add#forKey中)是无关紧要的,很少使用。设置为零。如果由于某种原因想要设置它,请将其设置为"任何字符串" (比方说,你的昵称)。另一方面......

  2. keyPath来电中的CABasicAnimation实际上是您正在动画的实际内容",换句话说,它实际上是一个属性图层(但只写为字符串)。

  3. 简而言之,add#forKey几乎总是零,这是无关紧要的。它与" keyPath"完全无关。 - 事实上他们都有"关键"在名称中纯属巧合,这两件事完全无关。

    你经常看到这两个混淆的代码(感谢愚蠢的命名),这会导致各种各样的问题。

    请注意,截至最近,您可以将animationDidStop与委托一起使用,请参阅以下@jack的答案!在某些情况下,这更容易;有时候使用完成块会更容易。如果您有许多不同的动画(通常是这种情况),只需使用完成块。

答案 5 :(得分:10)

对于那些在Google上找到此页面的人来说只是一个注释:您真的可以通过将动画对象的“委托”属性设置为将接收通知并在其中实现“animationDidStop”方法的对象来完成工作。 object的.m文件。我刚尝试过,它的确有效。我不知道为什么Joe Blow说这不是正确的方法。

答案 6 :(得分:10)

Swift 4 + 中,我刚刚将delegate添加为

class CircleView: UIView,CAAnimationDelegate {
...

let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.delegate = self//Set delegate

动画完成回调 -

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
     print("Animation END")
  }

答案 7 :(得分:1)

Swift 5.0

func blinkShadow(completion: @escaping (() -> Void)) {
    CATransaction.begin()
    let animation = CABasicAnimation(keyPath: "shadowRadius")
    animation.fromValue = layer.shadowRadius
    animation.toValue = 0.0
    animation.duration = 0.1
    animation.autoreverses = true
    CATransaction.setCompletionBlock(completion)
    layer.add(animation, forKey: nil)
    CATransaction.commit()
}

答案 8 :(得分:0)

您可以在设置CAAnimation对象时设置给定动画的名称。在animationDiStop中:完成后,只需比较提供的动画对象的名称,即可根据动画执行特定功能。

答案 9 :(得分:0)

对于2020年...

ValueAnimator,更新您的自定义属性。

https://github.com/Only-IceSoul/ios-jjvalueanimator

 class OnAnimationListener : AnimatorListener {

        weak var s : ViewController?

        init(_ ins: ViewController) {
            s = ins
        }
        func onAnimationStart(_ animation: Animator) {}
        func onAnimationEnd(_ animation: Animator) {

           print("end")
           s?.label.text = "end"

        }
        func onAnimationCancel(_ animation: Animator) {}
        func onAnimationRepeat(_ animation: Animator) {}

    }

答案 10 :(得分:0)

我在CAAnimation上编写了一个扩展,它为您提供了开始和完成的结束,因为我对实现委托感到厌烦,尤其是对于多个动画,您必须做一些可怕的事情,例如使用动画的键才能看到哪个动画正在调用委托-使这种事情变得非常简单。

它在GitHub上-Animation Actions

希望对某人有用!