【Swift/UIKit】CABasicAnimationの使い方!CAAnimationDelegate

この記事からわかること

  • Swift/UIKitUIViewアニメーションさせる方法
  • Core Animationフレームワーク役割
  • CABasicAnimation使い方違い
  • CAAnimationDelegateでアニメーションの開始終了検知する
  • 無限回転するアニメーションの実装方法

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

UIKitを使用したiOSアプリ開発でビューにアニメーションを実装する方法をまとめて行きます。

アニメーションを実装する方法

アニメーションを実装する方法はいくつか用意されています。それぞれの役割とは以下の通りになります。

今回はCore Animationフレームワークから提供されているCABasicAnimationの使い方をまとめていきます。

Core Animationフレームワークとは?

公式リファレンス:Core Animation
公式リファレンス:Core Animation Programming Guide

Core Animationフレームワークとはグラフィックレンダリングとアニメーションを提供するiOSとMac OS共通のフレームワークです。直接使用する機会は少ないですがiOSアプリにとってもインフラ部分になる大事なクラスです。

描画に特化しているのでイベント処理などを持たせることはできませんがその分描画速度が速く、GPUが処理を負担するためCPUへの負担も少ないのが大きな特徴になっています。

描画をGPUが担当するためBitmap形式でのデータ保存が必要になります。Core AnimationではBitmap形式でコンテンツを取り扱い、それをキャッシュ(「バッキングストア(backing store)」と呼ぶ)することで高速な描画を実現しています。

※Bitmapとは画像のデータ形式の1つでデータをピクセルの位置(座標)と色で管理する形式です。

まとめると「コンテンツを画像で管理することでGPUに処理を任せて高速に描画するためのフレームワーク」という感じでしょうか?

そしてCore Animationで肝になってくるのがCALayer(レイヤーオブジェクト)です。詳細に関しては以下の記事を参考にしてください。

CABasicAnimationの使い方

公式リファレンス:CABasicAnimationクラス

CABasicAnimationクラスはCore Animationフレームワークから提供されているアニメーションを実装するためのクラスです。こちらはCALayer(レイヤーオブジェクト)に対してアニメーションを付与していくのでUIViewを直接操作していたUIView.animateメソッドなどでアニメーションできなかったプロパティやより複雑な変化をさせることができます。

では先に実装方法を見てみます。まずは「透明度を0に、角を丸くするアニメーション」を付与してみます。

let square = UIView(frame: CGRect(x: 0, y:0, width: 150 , height: 150))
square.backgroundColor = .orange
square.center = self.view.center

// 透明度アニメーションの実装
let opacityAnimation = CABasicAnimation(keyPath: "opacity")
opacityAnimation.fromValue = 1
opacityAnimation.toValue = 0
opacityAnimation.duration = 2.0
square.layer.add(opacityAnimation, forKey: "opacityAnimation")

// 角丸アニメーションの実装
let cornerRadiusAnimation = CABasicAnimation(keyPath: "cornerRadius")
cornerRadiusAnimation.fromValue = 0
cornerRadiusAnimation.toValue = 30
cornerRadiusAnimation.duration = 2.0
square.layer.add(cornerRadiusAnimation, forKey: "cornerRadiusAnimation")

self.view.addSubview(square)
【Swift/UIKit】UIView.animateメソッドの使い方!アニメーションの実装

使い方

アニメーションを実装するにはCABasicAnimationインスタンスを生成します。イニシャライザの引数keyPathに渡すのは適当な文字列ではなく、プロパティのキーパス(名前)です。キーパスなので例えばスケールのX軸をアニメーションする場合はtransform.scale.xを、回転させたい場合はtransform.rotationを指定します。

let opacityAnimation = CABasicAnimation(keyPath: "opacity")

インスタンス化できたCABasicAnimationに対してアニメーションの設定をしていきます。fromValueプロパティでアニメーション開始時の値toValueアニメーション終了時の値を、durationアニメーションの継続時間を指定します。

// 開始の値
opacityAnimation.fromValue = 1
// 終了の値
opacityAnimation.toValue = 0
// アニメーション継続時間
opacityAnimation.duration = 2.0

最後にlayer(CALayer)プロパティにaddメソッドを使用してアニメーションを追加すればビューが描画されたタイミングでアニメーションが発火します。forKeyにはアニメーションを識別するための文字列を渡します。

square.layer.add(opacityAnimation, forKey: "opacityAnimation")

開始時間を遅らせる

アニメーションの開始時間を遅らせたい場合beginTimeプロパティに遅らせたい時間を渡します。 CACurrentMediaTime() + 1で1秒後にアニメーションを開始することができます。

opacityAnimation.beginTime = CACurrentMediaTime() + 1

逆再生

アニメーションを逆再生したい場合autoreversesプロパティにtrueを渡します。

opacityAnimation.autoreverses = true

アニメーションした値を戻さない

アニメーション完了後は自動で値が戻ってしまうので変化したままにしたい場合isRemovedOnCompletionプロパティにtrueを渡し、fillModeプロパティにCAMediaTimingFillMode.forwardsを渡します。

opacityAnimation.isRemovedOnCompletion = false
opacityAnimation.fillMode = CAMediaTimingFillMode.forwards

アニメーション開始・終了を検知する:CAAnimationDelegate

アニメーションの開始・終了を検知して処理を実行したい場合はCAAnimationDelegateプロトコルを使用します。animationDidStartデリゲートメソッドからアニメーションが開始したことをanimationDidStopからアニメーションが停止したことを検知することができます。

animationDidStopの引数からはアニメーションの抽象スーパークラスであるCAAnimation型と完全に終了したことを示すフラグを取得できます。

extension ViewController: CAAnimationDelegate {

    func animationDidStart(_ anim: CAAnimation) {
        print("アニメーションが開始されたよ")
    }

    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if flag {
            print("アニメーションが終了したよ")
            if let layer = anim.value(forKey: "square.layer") as? CALayer {
                layer.backgroundColor = UIColor.gray.cgColor
                layer.cornerRadius = 30
                layer.removeAnimation(forKey: "opacityAnimation")
            }
        }
    }
}

CAAnimation型を介して上記のようにアニメーション識別子でアニメーションを以下のsetValueメソッドで指定した識別子でCALayerインスタンスを取得することができます。

// 透明度アニメーションの実装
let opacityAnimation = CABasicAnimation(keyPath: "opacity")
opacityAnimation.fromValue = 1
opacityAnimation.toValue = 0
opacityAnimation.duration = 2.0
opacityAnimation.isRemovedOnCompletion = true
opacityAnimation.fillMode = CAMediaTimingFillMode.forwards
// デリゲートをセット
opacityAnimation.delegate = self
// CALayerを渡すように識別子を付与
opacityAnimation.setValue(square.layer, forKey: "square.layer")
square.layer.add(opacityAnimation, forKey: "opacityAnimation")
self.view.addSubview(square)

Viewを無限回転させてみる

独自のローディングビューなどを実装する際に利用できるViewが無限回転するアニメーションを実装するなら以下のおようになります。

let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
// 360度回転
rotationAnimation.toValue = Double.pi * 2.0
rotationAnimation.duration = 3.0
// アニメーションを累積許可
rotationAnimation.isCumulative = true
// アニメーション繰り返し回数に最大の有限数を指定
rotationAnimation.repeatCount = Float.greatestFiniteMagnitude
square.layer.add(rotationAnimation, forKey: "rotationAnimation")
self.view.addSubview(square)
【Swift/UIKit】CABasicAnimationの使い方!

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index