iOS
Swift

UIViewのアニメーションを永続的に行う方法

背景

UIViewクラスにはanimateというメソッドが用意されており、下記のようにシンプルにアニメーションを実装することができます。

testViewを3秒間かけて下に50point移動する
UIView.animate(withDuration: 3) {
    self.testView.frame.origin.y += 50
}

ただしこのようなアニメーションを繰り返し行いたい場合、例えば5秒毎にViewを上下に行ったり来たりさせるといったアニメーションを実装するには、若干の工夫が必要になります。本記事では、Timerクラスを用いて永続的なアニメーションを行う手法を紹介します。

アニメーションの実装

まず、下記のようにアニメーションを行うメソッドを定義しておきます。この例では、testViewのframe.origin.yが0の場合は下に50point移動し、そうでない場合は0の位置に移動するというアニメーションを0.3秒で行うように指定しています。
※後にselectorとして使用可能なように、メソッドの接頭詞に@objcを付けています。

testView.frame.origin.yが0なら+50、そうでないなら0に移動
@objc func animate() {
    UIView.animate(withDuration: 0.3) {
        if self.testView.frame.origin.y == 0 {
            self.testView.frame.origin.y += 50
        } else {
            self.testView.frame.origin.y = 0
        }
    }
}

Timerの設定

次にTimerの設定を行います。下記の例では、5秒毎にanimateメソッドを呼び続けるようにTimerをセットしています。こうすることで、一定間隔で上記のanimateメソッドが呼び出され、testViewが上下に50ポイントずつ動き続けるアニメーションを実装することができます。

5秒毎にanimateメソッドを呼ぶ
var animationTimer: Timer?

override func viewDidLoad() {
    super.viewDidLoad()

    self.animationTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(self.animate), userInfo: nil, repeats: true)
}

注意点

Timerが不要となったタイミング(testViewが非表示になった場合等)で、下記のようにinvalidateを呼んでTimerを無効化しておくとよいでしょう。invalidateを行わずにTimer.scheduledTimerを繰り返しセットし続けたりすると、クラッシュの原因となるため注意してください。

animationTimerを無効化する
self.animationTimer?.invalidate()

例えば独自のUIViewにTimerを持たせていた場合、下記のようにすることでViewが非表示になるタイミングでTimerをオフにできます。

UIViewが非表示になるタイミングでTimerを無効化する
override func willMove(toWindow newWindow: UIWindow?) {
    super.willMove(toWindow: newWindow)

    if (newWindow == nil) {
        self.animationTimer?.invalidate()
    }
}