アニメーション、CABasicAnimationまたはCAAnimationGroupをチェーンする必要がありますが、その方法がわかりません。唯一の方法は、すべてのアニメーションが同じレイヤーに対して同時に実行されることです。
どうすればいいですか?
たとえば、コンテンツが車の画像に設定されているレイヤー:
1番目:Xポイントを右に移動します
2番目:90ªを左に回転します
3番目:Xポイントを移動
4番目:レイヤーをスケーリングします
このアニメーションはすべて秘密裏に実行する必要がありますが、実行できません:S
ところで:私は英語ではありません。文法を間違えたらごめんなさい:D
tl; dr:前回の終了後に、各アニメーションを手動で追加する必要があります。
シーケンシャルアニメーションを追加する組み込みの方法はありません。あなたcouldは、各アニメーションの遅延を以前のすべてのアニメーションの合計に設定できましたが、お勧めしません。
代わりに、すべてのアニメーションを作成し、実行する予定の順序で(配列をキューとして使用して)可変配列に追加します。次に、すべてのアニメーションへのアニメーションデリゲートとして自分自身を設定することにより、アニメーションが終了するたびにanimationDidStop:finished:
コールバックを取得できます。
そのメソッドでは、最初のアニメーション(次のアニメーションを意味する)を配列から削除し、それをレイヤーに追加します。あなたはデリゲートであるため、アニメーションが終了すると2番目のアニメーションが表示されます。その場合、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:
とvalueForKey:
だけで機能します)。
Davidが提案することは問題なく機能しますが、別の方法をお勧めします。
すべてのアニメーションが同じレイヤーにある場合は、アニメーショングループを作成し、各アニメーションに異なる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;
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
animation1.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を使用します。すべてのアニメーションのキーの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];
}
}