質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

Q&A

解決済

2回答

3393閲覧

ホームボタン押下時のアニメーションの処理

lyzmfeqpxs54

総合スコア237

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Swift 2

Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

0グッド

0クリップ

投稿2016/06/23 13:48

swiftに関する質問です。
現在下記のように20秒かけてバーを減少さるアニメーションを行っています。
ホームボタン押下時にこのバーを一度停止したいためAppDelegate.swiftでtimerbarstop()を実行しています。

再び画面を開いた際にバーの減少を停止状態から再開するように考えているのですが、現状、再び画面を開くとバーが消えてしまっている状態です。

状況だけで大変恐縮ですが、どのようなことが考えられるかをご教示いただけないでしょうか。

よろしくお願いいたします。

swift

1 2KenteiViewController.swift 3 4 5private var myImageView: UIImageView! 6 7 func timerbar(){ 8 let barHeight = scHei*0.011 9 let barWidth = scWid*0.58 10 let barXPosition = scWid*0.14 11 let barYPosition = scHei*0.367 12 let barXPositionEnd = barXPosition + barWidth 13 // UIImageViewを作成する. 14 myImageView = UIImageView() 15 // 表示する画像を設定する. 16 let myImage = UIImage(named: "jikanbar.jpg") 17 // 画像をUIImageViewに設定する. 18 myImageView.image = myImage 19 // 画像の表示する座標を指定する. 20 myImageView.frame = CGRectMake(barXPosition ,barYPosition ,barWidth ,barHeight) 21 // UIImageViewをViewに追加する. 22 self.view.addSubview(myImageView) 23 24 UIView.animateWithDuration(20, delay: 0.0, options : UIViewAnimationOptions.CurveLinear, animations: {() -> Void in 25 self.myImageView.frame = CGRectMake(barXPositionEnd, barYPosition, 0, barHeight) 26 27 }, 28 completion: {(finished: Bool) -> Void in 29 // アニメーション終了後の処理 30 }) 31 32 } 33 34 //制限時間バーを停止するメソッド 35 func timerbarstop(){ 36 let pausedTime : CFTimeInterval! = myImageView?.layer.convertTime(CACurrentMediaTime(), fromLayer: nil) 37 myImageView?.layer.speed = 0.0 38 myImageView?.layer.timeOffset = pausedTime 39 }

swift

1AppDelegate.swift 2 3func applicationDidEnterBackground(application: UIApplication) { 4 // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 5 // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 6 let kentei = KenteiViewController() 7 kentei.timerbarstop() 8 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

間違って投稿したので削除

投稿2016/06/28 13:50

編集2016/06/28 13:51
u39ueda

総合スコア950

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

まず、提示されたコードだとapplicationDidEnterBackground()内で新たにKenteiViewControllerを作ってしまっているため、アニメーションの停止自体ができていません。
すでに存在しているオブジェクトがあるはずなのでそちらのtimerbarstop()を呼び出すようにしなければ意味がありません。

その修正をしてもアニメーションが消えるのは変わりません。
バックグラウンドに行くとアニメーションが消えてしまうからみたいです。(知らなかった…)

それの回答ですがやっぱり StackOverflow にあります。

簡単に言うと、バックグラウンドに行く時(applicationDidEnterBackground())にanimationForKey()でCAAnimationオブジェクトをメンバ変数等に保存しておいて、フォアグラウンドに復帰する際(applicationWillEnterForeground())に再度 addAnimation(forKey:) で追加し直してあげればいいです。

6/26追記

一応動かせるコードを載せます。

  • AppDelegateからViewControllerを探すのは面倒ですし画面構成によって探し方も変わるのでViewController内で通知を受信してアニメーションをポーズさせるように変更しました。
  • アニメーション開始のコードがなかったのでviewDidAppearでとりあえず開始するようにしました。
  • scHeiとscWidってなんなのかわかんなかったのでとりあえず画面サイズっぽい値を入れてみました。

Swift

1KenteiViewController.swift 2 3class KenteiViewController: UIViewController { 4 5 private var myImageView: UIImageView! 6 var pausedAnimations: [String: CAAnimation]? 7 8 override func viewDidLoad() { 9 super.viewDidLoad() 10 11 // バックグラウンドへ遷移する通知の受信開始 12 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(KenteiViewController.didEnterBackgroundNotification(_:)), name: UIApplicationDidEnterBackgroundNotification, object: nil) 13 // バックグラウンドから復帰する通知の受信開始 14 NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(KenteiViewController.willEnterForegroundNotification(_:)), name: UIApplicationWillEnterForegroundNotification, object: nil) 15 } 16 17 deinit { 18 // バックグラウンドへ遷移する通知の受信解除 19 NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidEnterBackgroundNotification, object: nil) 20 // バックグラウンドから復帰する通知の受信解除 21 NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationWillEnterForegroundNotification, object: nil) 22 } 23 24 // バックグラウンドへ遷移する通知受信時の処理 25 func didEnterBackgroundNotification(notification: NSNotification) { 26 guard let myImageView = myImageView else { return } 27 28 // myImageViewのレイヤに設定されているCAAnimationオブジェクトをpausedAnimationsに保持する 29 var animations = [String: CAAnimation]() 30 myImageView.layer.animationKeys()?.forEach({ (key) in 31 animations[key] = myImageView.layer.animationForKey(key) 32 }) 33 if !animations.isEmpty { 34 pausedAnimations = animations 35 pauseLayer(myImageView.layer) 36 } 37 } 38 39 // バックグラウンドから復帰する通知受信時の処理 40 func willEnterForegroundNotification(notification: NSNotification) { 41 guard let myImageView = myImageView else { return } 42 43 if let animations = pausedAnimations { 44 // pausedAnimationsに保持していたCAAnimationオブジェクトをmyImageViewのレイヤに追加し直す 45 animations.forEach({ (key, animation) in 46 myImageView.layer.addAnimation(animation, forKey: key) 47 }) 48 self.pausedAnimations = nil 49 resumeLayer(myImageView.layer) 50 } 51 } 52 53 override func viewDidAppear(animated: Bool) { 54 super.viewDidAppear(animated) 55 56 // とりあえずココでアニメーション開始 57 timerbar() 58 } 59 60 // よくわかんないので画面サイズっぽい値にする 61 let scHei: CGFloat = 480.0 62 let scWid: CGFloat = 320.0 63 64 func timerbar(){ 65 let barHeight = scHei*0.011 66 let barWidth = scWid*0.58 67 let barXPosition = scWid*0.14 68 let barYPosition = scHei*0.367 69 let barXPositionEnd = barXPosition + barWidth 70 // UIImageViewを作成する. 71 myImageView = UIImageView() 72 // 表示する画像を設定する. 73 let myImage = UIImage(named: "jikanbar.jpg") 74 // 画像をUIImageViewに設定する. 75 myImageView.image = myImage 76 // 画像の表示する座標を指定する. 77 myImageView.frame = CGRectMake(barXPosition ,barYPosition ,barWidth ,barHeight) 78 // UIImageViewをViewに追加する. 79 self.view.addSubview(myImageView) 80 81 UIView.animateWithDuration(20, delay: 0.0, options : UIViewAnimationOptions.CurveLinear, animations: {() -> Void in 82 self.myImageView.frame = CGRectMake(barXPositionEnd, barYPosition, 0, barHeight) 83 }, completion: {(finished: Bool) -> Void in 84 // アニメーション終了後の処理 85 }) 86 87 } 88 89 func pauseLayer(layer: CALayer) { 90 let pausedTime = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) 91 layer.speed = 0.0 92 layer.timeOffset = pausedTime 93 } 94 95 func resumeLayer(layer: CALayer) { 96 let pausedTime = layer.timeOffset 97 layer.speed = 1.0 98 layer.timeOffset = 0.0 99 layer.beginTime = 0.0 100 let timeSincePause = layer.convertTime(CACurrentMediaTime(), fromLayer: nil) - pausedTime 101 layer.beginTime = timeSincePause 102 } 103} 104

投稿2016/06/23 15:24

編集2016/06/26 05:24
u39ueda

総合スコア950

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lyzmfeqpxs54

2016/06/24 00:57

ご回答ありがとうございます。不勉強で度々の質問をお許しください。 ご教示いただいた「CAAnimationオブジェクトをメンバ変数等に保存しておいて」の部分ですがUIView.animateWithDurationを保存する方法があるのでしょうか。それともCABasicAnimationを使用し「let scaleDown = CABasicAnimation(keyPath: "transform.scale")」のような方法をとらなければならないのでしょうか。
u39ueda

2016/06/24 03:48

UIView.animateWithDurationを使ってアニメーションした場合でも、内部ではCoreAnimationを使っているためレイヤにCAAnimationオブジェクトがセットされています。 取得するにはanimationKeys()とanimationForKey()を使用します。
lyzmfeqpxs54

2016/06/25 01:05

度々の質問失礼いたします。CAAnimationについてずっと調べていたのですが、全くとっかかりすら掴めない状況です。大変恐縮なのですが、具体的なコードを教えていただくことは可能でしょうか。不勉強で本当に申し訳ございません。
u39ueda

2016/06/26 05:26

コードを追記しました。
lyzmfeqpxs54

2016/06/28 11:25

ご教示いただいたコードで無事解決いたしました! 何度もお手数をおかけして申し訳ありませんでした。 また、何かありました際にいろいろとご教示いただければ幸いです。 本当にありがとうございました。
lyzmfeqpxs54

2016/06/28 13:33

度々の質問大変恐縮ですが、最後に1点だけ質問をよろしいでしょうか。 ホームボタンで戻った際にcompletionのfinishedがfalseで返ってきてしまいます。 「completion: {(finished: Bool) -> Void in」の後に次のアニメーションの処理などを行いたいと考えているのため、ホームボタンで戻った際にfalseが返らないようにし、かつ、復帰後のアニメーション終了時にtrueを返すような方法を取ることは可能でしょうか。 ご教示いただければ幸いです。
u39ueda

2016/06/28 13:51

追加し直したとはいえ、元のアニメーション自体はキャンセルされていますので完了ブロックがfalseで呼ばれてしまうのは当然と言えば当然の動作なんですよね。 なので、 > ホームボタンで戻った際にfalseが返らないようにし、かつ、復帰後のアニメーション終了時にtrueを返すような方法 は不可能と思います。
lyzmfeqpxs54

2016/06/28 15:42

やはり不可能ですか……。度々のご回答ありがとうございました。 また、よろしくお願いいたします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問