如何在animationDidStop委托中识别CAAnimation?

Bat*_*gar 102 iphone core-animation

我遇到了一个问题,我有一系列重叠的CATransition/CAAnimation序列,所有这些都是我需要在动画停止时执行自定义操作,但我只需要一个dynamicDidStop的委托处理程序.

但是,我遇到了一个问题,似乎没有办法在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];
}
Run Code Online (Sandbox Code Playgroud)

在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.
 }
Run Code Online (Sandbox Code Playgroud)

另一方面是它允许您将状态保持在键值配对系统中,而不必将其存储在您的委托类中.代码越少越好.

请务必查看关键值对编码Apple参考.

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

谢谢, - 巴特

voc*_*aro 91

巴特加的技术太复杂了.为什么不利用addAnimation中的forKey参数?它的目的是为了这个目的.只需取出对setValue的调用并将键字符串移动到addAnimation调用即可.例如:

[[hearingAidHalo layer] addAnimation:animation forKey:@"Throb"];
Run Code Online (Sandbox Code Playgroud)

然后,在animationDidStop回调中,您可以执行以下操作:

if (theAnimation == [[hearingAidHalo layer] animationForKey:@"Throb"]) ...
Run Code Online (Sandbox Code Playgroud)

  • 不起作用 - 在调用停止选择器时,动画不再存在.你得到一个空参考. (16认同)
  • Adam,请参阅下面的jimt的答案 - 你必须设置`anim.removedOnCompletion = NO;`这样当`-animationDidStop:finished:`被调用时它仍然存在. (7认同)
  • 这是对forKey:参数的误用,并且不需要它.Batgar正在做的事情是完全正确的 - 键值编码允许您将任意数据附加到动画中,因此您可以轻松识别它. (3认同)
  • 这很光滑,而且更容易,谢谢特雷弗. (2认同)

Dun*_*n C 46

我想出了一个更好的方法来完成CAAnimations的完成代码:

我为一个块创建了一个typedef:

typedef void (^animationCompletionBlock)(void);
Run Code Online (Sandbox Code Playgroud)

我用来为动画添加块的键:

#define kAnimationCompletionBlock @"animationCompletionBlock"
Run Code Online (Sandbox Code Playgroud)

然后,如果我想在CAAnimation完成后运行动画完成代码,我将自己设置为动画的委托,并使用setValue:forKey为动画添加一段代码:

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

然后,我实现了一个animationDidStop:finished:方法,它检查指定键的块并在找到时执行:

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

这种方法的优点在于您可以在创建动画对象的同一位置编写清理代码.更好的是,由于代码是一个块,它可以访问定义它的封闭范围内的局部变量.您不必乱用设置userInfo词典或其他类似的废话,也不必编写一个不断增长的animationDidStop:finished:方法,当您添加不同类型的动画时,它会变得越来越复杂.

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

  • 有人还为CAAnimation组建了一个类别:http://github.com/xissburg/CAAnimationBlocks (7认同)
  • 我很确定在将它设置为属性值之前,你需要一个[块复制]块. (3认同)

jim*_*imt 33

第二种方法只有在运行之前明确将动画设置为在完成时被删除时才有效:

CAAnimation *anim = ...
anim.removedOnCompletion = NO;
Run Code Online (Sandbox Code Playgroud)

如果您没有这样做,您的动画将在完成之前被删除,并且回调将无法在字典中找到它.

  • 这应该是评论,而不是答案. (10认同)
  • 我想知道是否有必要在removeAnimationForKey之后显式删除它? (2认同)

Tib*_*abo 31

所有其他答案都太复杂了!为什么不添加自己的密钥来识别动画?

这个解决方案非常简单,您只需要将自己的键添加到动画中(本例中为animationID)

插入此行以标识animation1:

[myAnimation1 setValue:@"animation1" forKey:@"animationID"];
Run Code Online (Sandbox Code Playgroud)

这个来识别animation2:

[myAnimation2 setValue:@"animation2" forKey:@"animationID"];
Run Code Online (Sandbox Code Playgroud)

像这样测试:

- (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
    }
}
Run Code Online (Sandbox Code Playgroud)

它不需要任何实例变量:


t0r*_*rst 13

要明确从上面隐含的内容(以及在浪费几个小时之后将我带到这里的原因):不要期望看到你分配的原始动画对象传回给你

 - (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)flag 
Run Code Online (Sandbox Code Playgroud)

当动画结束时,因为[CALayer addAnimation:forKey:]制作了动画的副本.

您可以依赖的是,您为动画对象提供的键控值仍然在与animationDidStop:finished:消息一起传递的副本动画对象中具有等效值(但不一定是指针等效).如上所述,使用KVC,您可以获得足够的存储和检索状态的范围.