CAAnimation終了時にアニメーションを区別して追加処理を行う
Core Animationを使用してアニメーションを実装する際に、アニメーション終了時に追加処理を実行させたいことがある。例えば、あるImageViewを回転させるアニメーションを行い回転終了時にその角度のまま静止させる、といったことをやりたい場合を考えてみよう。この場合、まずは回転対象のImageViewのレイヤーにaddAnimation:forKey:で回転アニメーションを追加し、デリゲートメソッドanimationDidStop:finished:内にアニメーション終了時の処理を記述する。
下のソースコード内にもコメントで記述しているが、この処理を実装する際にはいくつかの注意すべき点がある。
- アニメーションオブジェクトのdelegateを設定する。これを設定しなければ、デリゲートのanimationDidStop:finished:が呼ばれることはないので、アニメーション終了時の処理が実行されなくなってしまう。
- アニメーションオブジェクトのプロパティremovedOnCompletionにNOを設定する。このプロパティのデフォルトはYESなので、ユーザが明示的にNOを設定しなければアニメーション終了時にはこのアニメーションオブジェクトが自動的に削除されてしまい、animationDidStop:finished:で参照できなくなる。
複数のアニメーションオブジェクトのデリゲートに同じオブジェクトを設定すると、それらのアニメーションが終了するごとにanimationDidStop:finished:が一度ずつコールされる。場合によっては、animationDidStop:finished:内でアニメーションを区別し、それぞれのアニメーションごとに異なる処理を行いたいこともあるだろう。このような場合には、レイヤーに対してキーごとにanimationForKey:でアニメーションを問い合わせ、それにより取得したアニメーションオブジェクトをanimationDidStop:finished:の第1引数と比較することで、アニメーションを区別することができる。
- (void)sampleAnimation { CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform"]; // これを設定しなければanimationDidStop:finished:は呼ばれない。 rotateAnimation.delegate = self; // これを設定しなければanimationDidStop:finished:が呼ばれた時点で // このアニメーションはレイヤーから取り除かれている。 rotateAnimation.removedOnCompletion = NO; rotateAnimation.duration = 1.0; rotateAnimation.repeatCount = 0; CGFloat angle = 30.0; CATransform3D rotateTransform = CATransform3DMakeRotation(angle * M_PI / 180.0, 0, 0, 1.0); rotateAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; rotateAnimation.toValue = [NSValue valueWithCATransform3D:rotateTransform]; [imageView.layer addAnimation:rotateAnimation forKey:@"rotateAnimation"]; } // アニメーション終了時にこのメソッドがコールされる。 - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { // 複数のアニメーションのdelegateに同じオブジェクトを設定している場合には、 // 引数animが処理対象のアニメーションと一致するかをチェックし、 // 一致した場合にのみ処理を行う。 if (anim == [imageView.layer animationForKey:@"rotateAnimation"]) { // アニメーション終了時の状態で静止させるためには // アニメーションのtoValueプロパティを使用すればよい。 CABasicAnimation *basicAnim = (CABasicAnimation *)anim; imageView.layer.transform = [basicAnim.toValue CATransform3DValue]; [imageView.layer removeAnimationForKey:@"rotateAnimation"]; } }