[iOS] 画面遷移時のアニメーションキャンセルに注意

2015.11.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは!モバイルアプリサービス部の加藤です。

今回の内容はもしかしたらiOS開発者であれば常識かもしれません。

iOSで繰り返しアニメーションを実装していてアニメーションを行っている画面から他の画面に遷移して 再びアニメーションを行っていた画面に戻るとアニメーションが止まってしまっていることに気づきました。 実験として新規に簡単なアニメーションを行うアプリを作成し、本当に止まるのか試してみました。

開発環境

  • Xcode 7.1
  • iPhone 6s シミュレータ(iOS 9.1)

画面構成

アプリの画面構成は以下のようにタブで2画面を管理するようにしました。 こちらは1つめの画面で左上に配置しているビューがアニメーション対象のビューです。 STARTボタンをタップするとアニメーションを開始するようにします。

screen-transition-cancel-animation_001

こちらは2つ目の画面です。遷移先として使うだけなので特に処理は行いません。 screen-transition-cancel-animation_002

アニメーションのコーディング

STARTボタンをタップした時のアクションメソッドを実装していきます。 self.subViewが1つ目の画面の左上に配置したビューです。 ボタンをタップするとビューが左右に行ったり来たりします。 オプションでUIViewAnimationOptionRepeatを指定することでアニメーションを繰り返しています。

- (IBAction)userDidTapStartButton:(id)sender {
    CGRect toFrame = CGRectOffset(self.subView.frame, 100.0f, 0.0f);
    
    [UIView animateWithDuration:3
                          delay:0
                        options:UIViewAnimationOptionAutoreverse | UIViewAnimationOptionRepeat
                     animations:^{
                         self.subView.frame = toFrame;
                     }
                     completion:^(BOOL finished) {
                         if (finished) {
                             NSLog(@"animation completion finished.");
                         } else {
                             NSLog(@"animation completion NOT finished.");
                         }
                     }];
}

アニメーション中に画面遷移

実装したSTARTボタンをタップしてアニメーションを行っている最中に2つ目の画面のタブをタップして遷移するとコンソールに下記ログが出力されました。

animation completion NOT finished.

このログは実装したアニメーションのcompletionブロックが引数finishedがNOの状態で呼ばれたことを意味しています。

引数finishedが何を意味するのかUIViewのクラスリファレンスを見ると、completeionブロックの説明に下記記載がありました。

This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called.

finishedはcompletionハンドラが呼ばれた時にアニメーションが完了しているかどうかを表しています。 つまりfinishedがNOということはアニメーションが途中でキャンセルされたことを意味します。 実際に再び1つ目の画面に戻ってみるとアニメーションが止まってしまっていました。

ちなみにアニメーション中に [self.subView.layer removeAllAnimations]を呼んでアニメーションを削除しても同じようにcompletionブロックが引数finishedがNOの状態で呼ばれます。

まとめ

ということで繰り返しアニメーションを実装している場合は画面遷移時のアニメーションキャンセルに注意する必要がありそうです。 特に通信時のローディングアニメーションを自前で実装している場合などが該当するかと思います。 必要に応じてviewDidAppear:などでアニメーションを再開するなどの対処が必要です。

参考