链接核心动画动画

时间:2009-12-15 16:06:43

标签: objective-c cocoa core-animation

核心动画上下文中链接动画的最优雅和模块化方式是什么?

我的意思是做动画,当其他完成时开始(例如,更改position然后opacity)。正常方法是直接更改属性:

layer.position = new_point;
layer.opacity = 0.0f;

但这将同时进行。我想让一个人等一下。

那么为不同的对象链接动画呢?我读过关于CATransaction的用法如下:

[CATransaction begin]
layer1.property = new_property;
[CATransaction begin]
layer2.property2 = new_property2;
[CATransaction commit];
[CATransaction commit];

但它似乎不起作用..

6 个答案:

答案 0 :(得分:76)

您还可以使用动画分组并使用动画的beginTime字段。尝试这样的事情:

CABasicAnimation *posAnimation = [CABasicAnimation animationWithKeyPath:@"position"];
[posAnimation setFromValue:[NSNumber numberWithFloat:0.0]];
[posAnimation setToValue:[NSNumber numberWithFloat:1.0]];
// Here's the important part
[posAnimation setDuration:10.0];
[posAnimation setBeginTime:0.0];

CABasicAnimation *borderWidthAnimation = [CABasicAnimation animationWithKeyPath:@"borderWidth"];
[borderWidthAnimation setFromValue:[NSNumber numberWithFloat:0.0]];
[borderWidthAnimation setToValue:[NSNumber numberWithFloat:1.0]];
// Here's the important part
[borderWidthAnimation setDuration:10.0];
[borderWidthAnimation setBeginTime:5.0];

CAAnimationGroup *group = [CAAnimationGroup animation];
[group setDuration:10.0];
[group setAnimations:[NSArray arrayWithObjects:posAnimation, borderWidthAnimation, nil]];

[layer addAnimation:group forKey:nil];

请注意,整个动画的持续时间为10秒。第一个从第二个0开始,第二个从第5个开始。

答案 1 :(得分:5)

正如Matt指出的那样,您可以为具有不同开始时间的同一层创建包含不同动画的动画组。您还可以为独立的CAAnimation对象或CAAnimation组设置委托,并且在每个动画完成后,它将调用animationDidStop:finished:委托方法(请注意,作为组的一部分的动画获胜不要打电话给他们的代理animationDidStop:finished:方法。

我发现了一个很酷的技巧,它使CAAnimation animationDidStop:finished:方法更强大。我使用方法setValue:forKey:将一个代码块添加到一个独立的动画或动画组,使用键@“animationCompletionBlock”。然后我编写了一个通用的animationDidStop:finished:方法来检查刚刚完成的@“animationCompletionBlock”键的动画,如果找到它,则在那里执行代码块。

在github上查看这个项目,了解该技术的一个实例:

CAAnimation demo with completion blocks

您还可以在

中设置一组动画
[CATransaction begin];
//...
[[CATransaction commit];

阻止,如你所说。执行此操作时,可以使用CATransaction类方法setCompletionBlock:在当前事务组中的所有动画完成时调用代码块。然后,一个事务的完成块可以触发下一个事务。

答案 2 :(得分:1)

我使用setCompletionBlock方法将其关闭以定义一个闭包,当第一个动画完成时触发下一个动画:

[CATransaction begin]
layer1.property = new_property;
CATransaction.setCompletionBlock {
    [CATransaction begin]
    layer2.property2 = new_property2;
    [CATransaction commit];
}
[CATransaction commit];

答案 3 :(得分:0)

我不相信你可以像在你的例子中那样“嵌套”CA动画。

您需要为动画指定委托,并将第二个“转换”放在委托的animationDidStop:finished:选择器中。

可能想看一下Apple的Animation Types & Timing Programming Guide

答案 4 :(得分:0)

我一直希望单独设置每个动画的开始和结束时间是这样的:

我使用了A2DynamicDelegate(其开发现在发生在BlocksKit - Repo,他知道为什么< _<)在CAAnimation上的类别中实现completionBlock属性。

这使我能够做到这样的事情:

CAAnimation *a = ...
CAAnimation *b = ...
CAAnimation *c = ...

a.completionHandler = ^{
    [self.layer addAnimation:b forKey:@"foo"];
    [self.layer addAnimation:c forKey:@"bar"];
};

更灵活:)

我上传了完成处理程序here的代码。但是看一下头文件中的通知。我真的很困惑为什么这个方法没有被调用。

答案 5 :(得分:-1)

不包括我的“工具链”中的所有“技巧”,这个例子不是直接复制/可行的......但它确实为“链式”动画显示了一个非常简单的策略..

CATransform3D trans = m34();  // define chain-wide constants.
// Name your "stack". My "nextObject" returns arr[i]->done == nil. 
NSArray *layerStack = layer.sublayers;
//define a block, that "takes" a layer as it's argument.
void(^__block ChainBlock)(CALayer*) = ^(CALayer *m) { 
// animations, transforms, etc for each inividual "step".
    [m animate:@"transform" 
          // These are just NSValue-wrapped CAT3D's
          from:AZV3d(CATransform3DRotate(trans,  0,1,0,0)) 
            to:AZV3d(CATransform3DRotate(trans,1.5,1,0,0)) 
          time:2    // total time == each step * layerStack.count
         eased:kCAMediaTimingFunctionEaseOut
    completion:^{   // In completion, look for "next" layer.
                    CAL*  m2 = [layers nextObject]; 
// If there is "another" layer, call this block, again... with it.
                      if (m2)  chainAnis(m2);
// Otherise,you're done.  Cleanup, toggle values, whatevs.
                     else self.finishedProperty = YES;
    }];
};
// Give the block we just defined your "first" layer.
ChainBlock(layerStack[0]);  // It will recursively feed itself.

这显然取决于一些“外部魔法”,但这个概念很简单,并且(通过依赖性)消除了“处理”任何类型的粗略授权的需要。特别是{ {1}}等类别来自伟大的FunSize Framework, on Github