我需要链接动画、CABasicAnimation 或 CAAnimationGroup 但我不知道该怎么做,我唯一要做的就是所有动画同时针对同一层执行。
我怎么能做到?
例如,其内容设置为汽车图像的图层:
第一:向右移动X点
第二:向左旋转 90ª
第三:移动X点
第四:缩放图层
所有这些动画都必须以安全的方式执行,但我做不到:S
顺便说一句:我不是英语,如果我在语法上犯了一些错误,对不起:D
我需要链接动画、CABasicAnimation 或 CAAnimationGroup 但我不知道该怎么做,我唯一要做的就是所有动画同时针对同一层执行。
我怎么能做到?
例如,其内容设置为汽车图像的图层:
第一:向右移动X点
第二:向左旋转 90ª
第三:移动X点
第四:缩放图层
所有这些动画都必须以安全的方式执行,但我做不到:S
顺便说一句:我不是英语,如果我在语法上犯了一些错误,对不起:D
大卫建议的工作很好,但我会推荐一种不同的方式。
如果你所有的动画都在同一层,你可以创建一个动画组,并让每个动画有一个不同的beginTime
,其中第一个动画从beginTime
0 开始,每个新动画在之前动画的总持续时间之后开始。
但是,如果您的动画位于不同的图层上,则不能使用动画组(动画组中的所有动画都必须作用于同一图层。)在这种情况下,您需要提交单独的动画,每个动画都有beginTime
一个从 偏移CACurrentMediaTime()
,例如:
CGFloat totalDuration = 0;
CABasicAnimation *animationOne = [CABasicAnimation animationWithKeyPath: @"alpha"];
animationOne.beginTime = CACurrentMediaTime(); //Start instantly.
animationOne.duration = animationOneDuration;
...
//add animation to layer
totalDuration += animationOneDuration;
CABasicAnimation *animationTwo = [CABasicAnimation animationWithKeyPath: @"position"];
animationTwo.beginTime = CACurrentMediaTime() + totalDuration; //Start after animation one.
animationTwo.duration = animationTwoDuration;
...
//add animation to layer
totalDuration += animationTwoDuration;
CABasicAnimation *animationThree = [CABasicAnimation animationWithKeyPath: @"position"];
animationThree.beginTime = CACurrentMediaTime() + totalDuration; //Start after animation three.
animationThree.duration = animationThreeDuration;
...
//add animation to layer
totalDuration += animationThreeDuration;
tl; dr:您需要在之前的完成后手动添加每个动画。
没有内置的方式来添加顺序动画。您可以将每个动画的延迟设置为所有先前动画的总和,但我不建议这样做。
相反,我会创建所有动画,并按照它们应该运行的顺序将它们添加到可变数组(使用数组作为队列)。然后通过将自己设置为所有动画的动画委托,您可以在animationDidStop:finished:
动画完成时获得回调。
在该方法中,您将从数组中删除第一个动画(即下一个动画)并将其添加到图层中。由于您是委托人,您将在该动画完成时获得第二个动画,在这种情况下,animationDidStop:finished:
回调将再次运行,并且下一个动画将从可变数组中删除并添加到图层中。
一旦动画数组为空,所有动画都将运行。
一些示例代码可以帮助您入门。首先,您设置所有动画:
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];
[animation setToValue:(id)[[UIColor redColor] CGColor]];
[animation setDuration:1.5];
[animation setDelegate:self];
[animation setValue:[view layer] forKey:@"layerToApplyAnimationTo"];
// Configure other animations the same way ...
[self setSequenceOfAnimations:[NSMutableArray arrayWithArray: @[ animation, animation1, animation2, animation3, animation4, animation5 ] ]];
// Start the chain of animations by adding the "next" (the first) animation
[self applyNextAnimation];
然后在委托回调中,您只需再次应用下一个动画
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)finished {
[self applyNextAnimation];
}
- (void)applyNextAnimation {
// Finish when there are no more animations to run
if ([[self sequenceOfAnimations] count] == 0) return;
// Get the next animation and remove it from the "queue"
CAPropertyAnimation * nextAnimation = [[self sequenceOfAnimations] objectAtIndex:0];
[[self sequenceOfAnimations] removeObjectAtIndex:0];
// Get the layer and apply the animation
CALayer *layerToAnimate = [nextAnimation valueForKey:@"layerToApplyAnimationTo"];
[layerToAnimate addAnimation:nextAnimation forKey:nil];
}
我正在使用自定义键layerToApplyAnimationTo
,以便每个动画都知道它的图层(它仅通过setValue:forKey:
and起作用valueForKey:
)。
这是 Swift 中的一个解决方案:
var animations = [CABasicAnimation]()
var animation1 = CABasicAnimation(keyPath: "key_path_1")
// animation set up here, I've included a few properties as an example
animation1.duration = 1.0
animation1.fromValue = 1
animation1.toValue = 0
animations.append(animation1)
var animation2 = CABasicAnimation(keyPath: "key_path_2")
animation2.duration = 1.0
animation2.fromValue = 1
animation2.toValue = 0
// setting beginTime is the key to chaining these
animation2.beginTime = 1.0
animations.append(animation2)
let group = CAAnimationGroup()
group.duration = 2.0
group.repeatCount = FLT_MAX
group.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
group.animations = animations
yourLayer.addAnimation(group, forKey: nil)
David 的方法或 beginTime 属性都可以用于链接动画。请参阅http://wangling.me/2011/06/time-warp-in-animation.html - 它阐明了beginTime和其他CAMediaTiming协议属性的使用。
使用 KVC。每个动画的 Key 的 setValue。之后在 animationDidStop 中,您可以定义哪些动画已停止并在链中下一个运行。
- (void)moveXrightAnimation {
CABasicAnimation* theAnimation = ...
[theAnimation setValue:@"movexright" forKey:@"animationID"];
//animation
}
- (void)rotate90leftAnimation {
CABasicAnimation* theAnimation = ...
[theAnimation setValue:@"rotate90left" forKey:@"animationID"];
//animation
}
- (void)moveXpointAnimation {
CABasicAnimation* theAnimation = ...
[theAnimation setValue:@"movexpoint" forKey:@"animationID"];
//animation
}
- (void)scaleAnimation {
CABasicAnimation* theAnimation = ...
[theAnimation setValue:@"scale" forKey:@"animationID"];
//animation
}
#pragma mark - CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
if([[anim valueForKey:@"animationID"] isEqual:@"movexright"]) {
[self rotate90leftAnimation];
}
if([[anim valueForKey:@"animationID"] isEqual:@"rotate90left"]) {
[self moveXpointAnimation];
}
if([[anim valueForKey:@"animationID"] isEqual:@"movexpoint"]) {
[self scaleAnimation];
}
}