[iOS] 画面遷移時のアニメーションキャンセルに注意
はじめに
こんにちは!モバイルアプリサービス部の加藤です。
今回の内容はもしかしたらiOS開発者であれば常識かもしれません。
iOSで繰り返しアニメーションを実装していてアニメーションを行っている画面から他の画面に遷移して 再びアニメーションを行っていた画面に戻るとアニメーションが止まってしまっていることに気づきました。 実験として新規に簡単なアニメーションを行うアプリを作成し、本当に止まるのか試してみました。
開発環境
- Xcode 7.1
- iPhone 6s シミュレータ(iOS 9.1)
画面構成
アプリの画面構成は以下のようにタブで2画面を管理するようにしました。 こちらは1つめの画面で左上に配置しているビューがアニメーション対象のビューです。 STARTボタンをタップするとアニメーションを開始するようにします。
こちらは2つ目の画面です。遷移先として使うだけなので特に処理は行いません。
アニメーションのコーディング
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:
などでアニメーションを再開するなどの対処が必要です。