objective-c 链接核心动画动画
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1908480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Chaining Core Animation animations
提问by Hyman
Which is the most elegant and modular way to chain animation in a Core Animationcontext?
在Core Animation上下文中链接动画的最优雅和模块化的方式是什么?
I mean to do animations that starts just when other finished (for example, changing positionand then opacity).. normal approach is to directly change properties:
我的意思是做在其他完成时开始的动画(例如,改变position然后opacity……正常的方法是直接改变属性:
layer.position = new_point;
layer.opacity = 0.0f;
but this will do them at the same time. I want to make one wait for the other.
但这将同时进行。我想让一个等待另一个。
And what about chaining animations for different objects? I've read about CATransactionused like:
那么不同对象的链接动画呢?我读过CATransaction类似的使用:
[CATransaction begin]
layer1.property = new_property;
[CATransaction begin]
layer2.property2 = new_property2;
[CATransaction commit];
[CATransaction commit];
but it doesn't seem to work..
但它似乎不起作用..
回答by Matt Long
You can also use animation grouping and use the beginTime field of the animation. Try something like this:
您还可以使用动画分组并使用动画的 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];
Notice that the duration of the entire animation is 10 seconds. The first one starts at second 0 and the second one starts at 5 seconds.
请注意,整个动画的持续时间为 10 秒。第一个从 0 秒开始,第二个从 5 秒开始。
回答by Duncan C
As Matt pointed out, you can create animation groups that consist of different animations for the same layer with different begin times. You can also set a delegate for stand-alone CAAnimationobjects or CAAnimationGroups and as each animation finishes it will call an animationDidStop:finished:delegate method (note that animations that are part of a group won't call their delegate's animationDidStop:finished:method.
正如马特指出的那样,您可以创建动画组,这些动画组由同一层的不同动画组成,具有不同的开始时间。您还可以为独立CAAnimation对象或CAAnimation组设置委托,当每个动画完成时,它将调用animationDidStop:finished:委托方法(请注意,属于组的动画不会调用其委托的animationDidStop:finished:方法。
I figured out a cool trick that makes using the CAAnimation animationDidStop:finished:method more powerful. I use the method setValue:forKey:to add a block of code to a stand-alone animation or animation group, with the key @"animationCompletionBlock". I then write a general animationDidStop:finished:method that checks the just-completed animation for a @"animationCompletionBlock" key, and if it finds it, execute the block of code there.
我想出了一个很酷的技巧,使使用该CAAnimation animationDidStop:finished:方法更强大。我使用该方法setValue:forKey:将代码块添加到独立动画或动画组中,键为@"animationCompletionBlock"。然后我编写了一个通用animationDidStop:finished:方法来检查刚刚完成的动画是否有 @"animationCompletionBlock" 键,如果找到它,则在那里执行代码块。
Take a look at this project on github for a working example of that technique:
查看 github 上的这个项目,了解该技术的一个工作示例:
CAAnimation demo with completion blocks
You an also Set a group of animations inside a
您还可以在一个内部设置一组动画
[CATransaction begin];
//...
[[CATransaction commit];
block, as you suggested. When you do that, you can using the CATransactionclass method setCompletionBlock:to invoke a block of code when all the animations in the current transaction group complete. The completion block for one transaction can then trigger the next transaction.
阻止,正如你所建议的。当您这样做时,您可以使用CATransaction类方法setCompletionBlock:在当前事务组中的所有动画完成时调用代码块。一个事务的完成块然后可以触发下一个事务。
回答by wcochran
I pull this off using the setCompletionBlockmethod to define a closure that triggers the next animation when the first one is finished:
我使用setCompletionBlock方法定义了一个闭包,当第一个动画完成时触发下一个动画:
[CATransaction begin]
layer1.property = new_property;
CATransaction.setCompletionBlock {
[CATransaction begin]
layer2.property2 = new_property2;
[CATransaction commit];
}
[CATransaction commit];
回答by Meltemi
I don't believe you can "nest" CA animations as you have in your example.
我不相信您可以像示例中那样“嵌套”CA 动画。
You need to specify a delegatefor the animation and put your second "transition" within the animationDidStop:finished:selector of the delegate.
您需要为动画指定一个委托,并将您的第二个“过渡”放在animationDidStop:finished:委托的选择器中。
Might want to have a look at Apple's Animation Types & Timing Programming Guide.
可能想看看 Apple 的Animation Types & Timing Programming Guide。
回答by Ahti
What I have always preferred to setting the begin and end time of each animation seperately is this:
我一直喜欢单独设置每个动画的开始和结束时间是这样的:
I used A2DynamicDelegate (whose development is now happening in the BlocksKit-Repo, who knows why <_<) to implement a completionBlock property in a Category on CAAnimation.
我使用 A2DynamicDelegate(其开发现在正在BlocksKit-Repo 中进行,谁知道为什么 <_<)在 CAAnimation 的类别中实现 completionBlock 属性。
This enabled me to do stuff like this:
这使我能够做这样的事情:
CAAnimation *a = ...
CAAnimation *b = ...
CAAnimation *c = ...
a.completionHandler = ^{
[self.layer addAnimation:b forKey:@"foo"];
[self.layer addAnimation:c forKey:@"bar"];
};
Much more flexible :)
更灵活:)
I've uploaded my code for completion handler here. Have a look at the notice in the header file though. I am really confused why the method isn't called.
我已经在这里上传了我的完成处理程序代码。不过,请查看头文件中的通知。我真的很困惑为什么不调用该方法。
回答by Alex Gray
Without including all the "tricks" up my "toolchain", this example isn't directly copy/pastable… but it does show a REALLY easy strategy for "chained" animations..
没有包括我的“工具链”中的所有“技巧”,这个例子不能直接复制/粘贴……但它确实展示了一个非常简单的“链接”动画策略。
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.
This obviously depends on some "external magic", but the concept is simple, and eliminates (through dependencies) the need to "deal with" ANY sort of gross delegation.In particular, the animate:from:to:time:easing:completion, etc. categories come from the great FunSize Framework, on Github.
这显然取决于一些“外部魔法”,但概念很简单,并且(通过依赖关系)消除了“处理”任何类型的粗暴委派的需要。特别是animate:from:to:time:easing:completion,等类别来自Github 上的伟大FunSize 框架。

