CALayer 的动画结束回调? ?

我想知道在哪里的回调(或者如果有什么)为动画在一个 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.

58693 次浏览

我回答了我自己的问题。你必须像这样使用 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:,你应该就可以开始了。谢天谢地,这个功能已经存在了

在设置 CAAnimation 对象时,可以设置给定动画的名称。在 animationDiStop: done 中,只需比较提供的 Animation 对象的名称,以便基于动画执行特定功能。

您可以使用 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];

对于那些在 Google 上找到这个页面的人来说,只需要注意: 你真的可以通过设置动画对象的“委托”属性来接收通知,并在该对象的。M 档案。我刚试过,很管用。我不知道为什么 Joe Blow 说那不是正确的方式。

浪费了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];

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

    // 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()

2018年。

再简单不过了。

别忘了 [weak self],不然你会撞车的。

func animeExample() {
    

CATransaction.begin()
    

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

CATransaction.setCompletionBlock{ [weak self] in
self?.animeExample()
self?.ringBell()
print("again...")
}
    

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

关键提示:

你的 必须的setCompletionBlock 之前someLayer.add

订单很重要! 这是 iOS 的怪癖。

在这个例子中,它只是再次调用自己。

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


任何刚接触 iOS 动画的人请注意:

  1. “键”(如 forKey)是 无关紧要,很少使用。设为零。如果你想设置它,设置为“任意字符串”。

  2. “ keyPath”实际上是 真正的“你正在制作的东西”。它是字面上的 层的属性,如“不透明度”,“背景色”等,但 以字符串形式写入。(你不能只是在那里输入“任何你想要的”,它必须是图层的一个实际属性的名称,并且,它必须是可动画的。)

重复一遍: “ key”(很少使用-只是设置为 nil)和“ keyPath”是完全不相关的。

您经常看到示例代码,其中这两个是 很困惑(由于愚蠢的命名) ,这会导致各种各样的问题。


注意,你可以选择使用委托,但是只使用完成块要容易得多,因为(A)它是自包含的,可以在任何地方使用; (B)你通常有多个动画,在这种情况下使用委托是一件无聊的事情。

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")
}

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()
}

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) {}


}

我在 CAAnimation 上写了一个扩展,给你一个开始和一个结束,因为我已经厌倦了实现委托,特别是对于多个动画,你不得不做一些可怕的事情,比如使用动画的键来查看哪个动画正在调用委托-使这种事情真的很容易。

在 GitHub-动画行动

希望对某些人有用!