如何将animationDidStop委托内识别CAAnimation?(How to identi

2019-06-18 06:31发布

我有一个问题,我有一系列重叠CATransition / CAAnimation序列,所有这一切,我需要进行自定义操作,当动画停止的,但我只是想一个委托处理程序animationDidStop。

但是,我有一个问题,有没有出现有一种方法来唯一标识animationDidStop代表每个CATransition / CAAnimation。

我通过暴露CAAnimation的一部分键/值系统解决了这个问题。

当您启动动画使用的CATransition / CAAnimation setValue方法来设置你的标识符和值使用时animationDidStop火灾:

-(void)volumeControlFadeToOrange
{   
    CATransition* volumeControlAnimation = [CATransition animation];
    [volumeControlAnimation setType:kCATransitionFade];
    [volumeControlAnimation setSubtype:kCATransitionFromTop];
    [volumeControlAnimation setDelegate:self];
    [volumeControlLevel setBackgroundImage:[UIImage imageNamed:@"SpecialVolume1.png"] forState:UIControlStateNormal];
    volumeControlLevel.enabled = true;
    [volumeControlAnimation setDuration:0.7];
    [volumeControlAnimation setValue:@"Special1" forKey:@"MyAnimationType"];
    [[volumeControlLevel layer] addAnimation:volumeControlAnimation forKey:nil];    
}

- (void)throbUp
{
    doThrobUp = true;

    CATransition *animation = [CATransition animation]; 
    [animation setType:kCATransitionFade];
    [animation setSubtype:kCATransitionFromTop];
    [animation setDelegate:self];
    [hearingAidHalo setBackgroundImage:[UIImage imageNamed:@"m13_grayglow.png"] forState:UIControlStateNormal];
    [animation setDuration:2.0];
    [animation setValue:@"Throb" forKey:@"MyAnimationType"];
    [[hearingAidHalo layer] addAnimation:animation forKey:nil];
}

在您的animationDidStop委托:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{

    NSString* value = [theAnimation valueForKey:@"MyAnimationType"];
    if ([value isEqualToString:@"Throb"])
    {
       //... Your code here ...
       return;
    }


    if ([value isEqualToString:@"Special1"])
    {
       //... Your code here ...
       return;
    }

    //Add any future keyed animation operations when the animations are stopped.
 }

这样做的另一个方面是,它可以让你保持,而不必储存到您的委托类状态键值配对系统。 代码越少,越好。

一定要检查出的键值对编码苹果参考 。

是否有在animationDidStop委托CAAnimation / CATransition识别更好的技术?

谢谢,--Batgar

Answer 1:

Batgar的技术是太复杂了。 为什么不采取addAnimation的forKey参数的优势在哪里? 它的目的是为这个目的。 刚拿出电话给setValue和钥匙串移到addAnimation通话。 例如:

[[hearingAidHalo layer] addAnimation:animation forKey:@"Throb"];

然后,在你animationDidStop回调,你可以这样做:

if (theAnimation == [[hearingAidHalo layer] animationForKey:@"Throb"]) ...


Answer 2:

我只是想出了一个更好的方式来为CAAnimations做完成代码:

我创建了一个块一个typedef:

typedef void (^animationCompletionBlock)(void);

而且我用一键块添加到动画:

#define kAnimationCompletionBlock @"animationCompletionBlock"

然后,如果我想要一个CAAnimation完成后运行动画完成的代码,我给自己定下了作为动画的代表,并添加代码来使用的setValue动画块:forKey:

animationCompletionBlock theBlock = ^void(void)
{
  //Code to execute after the animation completes goes here    
};
[theAnimation setValue: theBlock forKey: kAnimationCompletionBlock];

然后,我实施animationDidStop:完成:方法,用于检查在指定的密钥产生一个块,并且如果发现执行它:

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{
  animationCompletionBlock theBlock = [theAnimation valueForKey: kAnimationCompletionBlock];
  if (theBlock)
    theBlock();
}

这种方法的好处是,你可以在你创建动画对象相同的地方写清理代码。 更妙的是,因为代码是一个块,它可以访问在封闭范围内的局部变量中,它被定义。 你不必惹建立用户信息词典或其他这样的废话,而不必写日益增长的animationDidStop:完成:方法得到你添加不同种类的动画越来越复杂。

说实话,CAAnimation应该有一个完成的块属性内置到它,并且如果指定一个自动调用它的系统支持。 然而,上面的代码为您提供了只有几行额外的代码相同的功能。



Answer 3:

如果明确设置为被上完成删除你的动画运行它之前第二种方法只会工作:

CAAnimation *anim = ...
anim.removedOnCompletion = NO;

如果你不这样做,你的动画会得到它完成时删除之前,在字典中的回调将找不到它。



Answer 4:

所有其他的答案实在是太复杂! 你为什么不只是添加自己的密钥识别动画?

该解决方案是很容易你需要的是你自己的键添加到动画 (animationID在这个例子中)

插入此行,以确定动画1:

[myAnimation1 setValue:@"animation1" forKey:@"animationID"];

而这个识别animation2:

[myAnimation2 setValue:@"animation2" forKey:@"animationID"];

测试这样的:

- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
{
    if([[animation valueForKey:@"animationID"] isEqual:@"animation1"]) {
    //animation is animation1

    } else if([[animation valueForKey:@"animationID"] isEqual:@"animation2"]) {
    //animation is animation2

    } else {
    //something else
    }
}

它不需要任何实例变量



Answer 5:

作出明确什么是从上面暗示的(以及一些浪费小时后什么把我带到这里):不希望看到你分配通过传回给您原创动画对象

 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag 

当动画完成,因为[CALayer addAnimation:forKey:]让你的动画的副本。

什么可以依靠,是你给你的动画对象的键值,仍然存在与同等价值(但不一定是等价指针)与传递的副本动画对象animationDidStop:finished:消息。 正如上面提到的,使用KVC,你会得到充足的空间来存储和检索状态。



Answer 6:

我可以看到大多objc的答案,我会根据上面的最好的答案让一个为SWIFT 2.3。

一开始这将是不错的所有那些键存储在一个私人的结构所以它是类型安全和未来不断变化的它不会给你带来恼人的bug,只是因为你忘了在代码中到处进行更改:

private struct AnimationKeys {
    static let animationType = "animationType"
    static let volumeControl = "volumeControl"
    static let throbUp = "throbUp"
}

正如你可以看到我已经改变了变数/动画的名称,以便更清楚。 在创建动画时,现在设置这些键。

volumeControlAnimation.setValue(AnimationKeys.volumeControl, forKey: AnimationKeys.animationType)

(......)

throbUpAnimation.setValue(AnimationKeys.throbUp, forKey: AnimationKeys.animationType)

后来终于处理了当动画停止委托

override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
    if let value = anim.valueForKey(AnimationKeys.animationType) as? String {
        if value == AnimationKeys.volumeControl {
            //Do volumeControl handling
        } else if value == AnimationKeys.throbUp {
            //Do throbUp handling
        }
    }
}


Answer 7:

使用苹果的键值恕我直言,是这样的优雅的方式:它的具体意思是允许添加应用程序特定的数据对象。

其他更优雅的可能性是引用存储到您的动画对象,做一个指针比较来识别它们。



Answer 8:

对我来说,以检查是否2 CABasicAnimation对象是相同的动画,我用的keyPath功能究竟为。

如果([animationA的keyPath] == [animationB的keyPath])

  • 有没有必要设置的keyPath为CABasicAnimation,因为这将不再动画


Answer 9:

我喜欢用setValue:forKey :让我的动画视图的参考,它比试图唯一识别的ID的动画,因为同一种动画可以添加到不同的层更加安全。

这两者是等价的:

[UIView animateWithDuration: 0.35
                 animations: ^{
                     myLabel.alpha = 0;
                 } completion: ^(BOOL finished) {
                     [myLabel removeFromSuperview];
                 }];

这一个:

CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeOut.fromValue = @([myLabel.layer opacity]);
fadeOut.toValue = @(0.0);
fadeOut.duration = 0.35;
fadeOut.fillMode = kCAFillModeForwards;
[fadeOut setValue:myLabel forKey:@"item"]; // Keep a reference to myLabel
fadeOut.delegate = self;
[myLabel.layer addAnimation:fadeOut forKey:@"fadeOut"];
myLabel.layer.opacity = 0;

并在委托方法:

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    id item = [anim valueForKey:@"item"];

    if ([item isKindOfClass:[UIView class]])
    {
        // Here you can identify the view by tag, class type 
        // or simply compare it with a member object

        [(UIView *)item removeFromSuperview];
    }
}


Answer 10:

Xcode的9雨燕4.0

您可以使用键值涉及您加入到animationDidStop委托方法返回动画的动画。

声明一个字典包含所有活动的动画及相关的完成:

 var animationId: Int = 1
 var animating: [Int : () -> Void] = [:]

当您添加动画,为它设置一个键:

moveAndResizeAnimation.setValue(animationId, forKey: "CompletionId")
animating[animationId] = {
    print("completion of moveAndResize animation")
}
animationId += 1    

在animationDidStop,神奇的发生:

    let animObject = anim as NSObject
    if let keyValue = animObject.value(forKey: "CompletionId") as? Int {
        if let completion = animating.removeValue(forKey: keyValue) {
            completion()
        }
    }


文章来源: How to identify CAAnimation within the animationDidStop delegate?