Core Animation: 基礀、CALayerとiOSでのアニメーション

著者: IT Sectr 公開日: 2026-03-01 読了時間: 8 分

Core Animationは、CALayerレベルで動作し、GPUでコンテンツをレンダリングするAppleのローレベルアニメーションフレームワークです。Core AnimationはiOSとmacOSにおけるすべてのアニメーションの基礎です: UIKit、AppKit、SceneKit、SpriteKitはその上に構築されています。この記事では、CALayer、CABasicAnimation、CATransactionのアーキテクチャと実践的な技術について説明します。

メインポイント

  • CALayer — GPUでのコンテンツ表示を管理するCore Animationのベースクラス
  • CABasicAnimation — fromValueからtoValueまでの1つのCALayerプロパティのシンプルなアニメーション
  • CATransaction — 共通のdurationとcompletionを持つ単一トランザクションにアニメーションをグループ化
  • CAAnimation — CABasicAnimation、CAKeyframeAnimation、CAAnimationGroupが継承する抽象ベースクラス
  • Render server — GPU上でアニメーションフレームを補間する独立プロセス(backboardd)

Core Animationとは?

Core AnimationはAppleのグラフィックフレームワークで、Mac OS X 10.5 Leopard (2007)で導入され、iPhone OS (2007)の初期バージョンでiOSにポートされました。Core AnimationはGPU上でレイヤー(CALayer)のコンポジション、アニメーション、レンダリングを管理します。iOSの各UIViewには組み込みのCALayer (view.layer)があり、すべての描画はこれを通じて行われます。

Core Animationはインプリシットアニメーションの原理で動作します: いくつかのCALayerプロパティ変更は自動的にアニメートされます(position、bounds、opacity、backgroundColorのCABasicAnimation)。インプリシットアニメーションはデフォルトで0.25秒のdurationとeaseInOutカーブでCATransactionを使用します。

Apple WWDC 2024によると、Core AnimationはProMotionデバイスで最120 FPSまで処理し、GPUレンダリングにMetalを使用します。ティピカルなレイヤーのメモリフットプリントは1ピクセルあたり4バイト(RGBA) + ~100バイトのオーバーヘッドです。安定した60 FPSには、画面上のレイヤーを1000以下にすることが推奨されます。

CALayerのアーキテクチャ

CALayerはCore Animationの基礎です。各CALayerはビットマップコンテンツ(またはGPUテクスチャ参照)を含み、ジオメトリ(bounds、position、anchorPoint、transform、cornerRadius、borderWidth、shadow)を定義します。レイヤーはタッチイベントを処理しません — UIView/UIScrollViewが処理します。レイヤーはビュー階層を反映する階層構造(layer tree)を形成します。

Core Animationは3つのレイヤーツリーを管理します: model layer tree(実際のプロパティ)、presentation layer tree(アニメーション中の現在の表示)、render tree(GPUデータ)。Presentation layerはリアルタイムの中間アニメーション値を読み取るために使用されます。

CALayerのタイプ

CALayerには専門化されたサブクラスがあります: CAShapeLayer(ベクトルグラフィックス)、CAGradientLayer(グラデーション)、CATextLayer(テキスト)、CATiledLayer(タイルに分けられた大きな画像)、CAEAGLLayer/MetalLayer(OpenGL/Metal)。CAShapeLayerはCGPathサポートとstrokeStart/strokeEndアニメーションにより、カスタムアニメーションに最も人気があります。

CABasicAnimation — 基本プロパティのアニメーション

CABasicAnimationはCAAnimationのサブクラスで、CALayerの1つのプロパティを開始値(fromValue)から終了値(toValue)または相対変更(byValue)によってアニメートします。アニメーションはlayer.add(animation, forKey:)を通じてレイヤーに追加され、各フレームでアプリの参加なしにレンダサーバーで実行されます。

キー(keyPath)はプロパティを指定する文字列です: opacity、position、bounds、transform.rotation.z、cornerRadius、shadowOpacityなど。Core Animationは60以上のアニメート可能なkeyPathをサポートしています。カスタムプロパティには、CATransactionとpresentation layerが使用されます。

swift
import QuartzCore

// opacityとcornerRadiusのCABasicAnimation
func animateLayer() {
    let layer = CALayer()
    layer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
    layer.backgroundColor = UIColor.systemBlue.cgColor
    view.layer.addSublayer(layer)

    // 1. 透明度アニメーション
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. 角丸アニメーション
    let cornerAnim = CABasicAnimation(keyPath: "cornerRadius")
    cornerAnim.fromValue = 0
    cornerAnim.toValue = 50
    cornerAnim.duration = 2.0
    cornerAnim.autoreverses = true
    cornerAnim.repeatCount = .infinity

    layer.add(fadeAnim, forKey: "fade")
    layer.add(cornerAnim, forKey: "corner")
}

// ease-in-outでのpositionアニメーション
func moveLayer(_ layer: CALayer, to point: CGPoint) {
    let anim = CABasicAnimation(keyPath: "position")
    anim.fromValue = NSValue(cgPoint: layer.position)
    anim.toValue = NSValue(cgPoint: point)
    anim.duration = 0.6
    anim.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    anim.isRemovedOnCompletion = false
    anim.fillMode = .forwards
    layer.add(anim, forKey: "move")
    layer.position = point // model layerを更新
}

重要: CABasicAnimationは一時的な表示(presentation layer)です。アニメーションが完了すると、レイヤーはmodel layerの値に戻ります。最終状態を保持するには、isRemovedOnCompletion = false、fillMode = .forwardsを設定し、model layerを最終値に更新します。

CATransaction — アニメーションのグループ化

CATransactionはCore Animationのアニメーションを単一のトランザクションにグループ化するメカニズムです。CATransaction.begin()とCATransaction.commit()がトランザクションの範囲を定義します。トランザクション内では、共通パラメーター(duration、timingFunction、completionBlock、disableActions)を設定できます。CATransactionはCALayerのインプリシットアニメーションの基礎です。

インプリシットアニメーションは、CALayerプロパティがアニメーションブロックの外で変更された場合に発生します: layer.opacity = 0.5。Core Animationは自動的に現在のCATransaction(デフォルト 0.25 s)からのdurationを持つCABasicAnimationを作成します。インプリシットアニメーションを無効にするには、CATransaction.setDisableActions(true)を使用します。

swift
// CATransaction — グルーピングと完了
func groupedAnimation() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    CATransaction.setAnimationTimingFunction(
        CAMediaTimingFunction(name: .easeOut)
    )
    CATransaction.setCompletionBlock {
        print("All animations completed")
    }

    // トランザクション内のすべての変更はduration 1.5でアニメートされる
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// インプリシットアニメーションを無効化
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // アニメーションなし
    CATransaction.commit()
}

// CAShapeLayerプロパティをアニメート
func animateProgress(percentage: CGFloat) {
    CATransaction.begin()
    CATransaction.setAnimationDuration(0.8)
    CATransaction.setCompletionBlock {
        print("Progress updated to (percentage)%")
    }
    progressLayer.strokeEnd = percentage / 100.0
    CATransaction.commit()
}

Swiftコード例

Core AnimationはUIViewレイヤーを通じてUIKitと連携します。下の例はCAShapeLayerアニメーションを示しています — 弧の長さアニメーションとCABasicAnimationによるレイヤー回転を伴う円形プログレスです。

swift
import UIKit
import QuartzCore

class CircularProgressView: UIView {

    private let progressLayer = CAShapeLayer()

    override func layoutSubviews() {
        super.layoutSubviews()

        let path = UIBezierPath(
            arcCenter: CGPoint(x: bounds.midX, y: bounds.midY),
            radius: bounds.width / 2 - 10,
            startAngle: -.pi / 2,
            endAngle: 3 * .pi / 2,
            clockwise: true
        )

        progressLayer.path = path.cgPath
        progressLayer.strokeColor = UIColor.systemBlue.cgColor
        progressLayer.lineWidth = 8
        progressLayer.fillColor = nil
        progressLayer.strokeEnd = 0
        progressLayer.lineCap = .round
        layer.addSublayer(progressLayer)
    }

    func setProgress(_ value: CGFloat, animated: Bool = true) {
        if animated {
            CATransaction.begin()
            CATransaction.setAnimationDuration(0.6)
            CATransaction.setAnimationTimingFunction(
                CAMediaTimingFunction(name: .easeOut)
            )
            progressLayer.strokeEnd = min(max(value, 0), 1)
            CATransaction.commit()
        } else {
            progressLayer.strokeEnd = value
        }
    }
}

CAShapeLayerはstrokeEndプロパティを0から1までアニメートし、円形プログレスの“埋め”エフェクトを作り出します。duration 0.6とeaseOutのCATransactionによりアニメーションが滑らかになります。layer.lineCap = .roundは線の端を丸くし、より綺麗な視覚的な仕上がりにします。

よくある質問

Core AnimationとUIView.animateの違いは?

Core AnimationはCALayerレベルで動作し、CABasicAnimationとCATransactionによって制御されます。UIView.animateはCore Animationのハイレベルラッパーで、UIViewのプロパティに対するCABasicAnimationを自動的に作成します。Core Animationはより多くの制御を提供します: keyPath、timingFunction、fillMode、CATransactionによるグループ化。

Core Animationでのインプリシットアニメーションとは?

インプリシットアニメーションは、アニメート可能なCALayerプロパティがアニメーションブロックの外で変更された場合に発生する自動アニメーションです。例えば、layer.opacity = 0.5は0.25 sのdurationでCABasicAnimationを作成します。インプリシットアニメーションはCATransactionで管理され、setDisableActions(true)で無効にできます。

カスタムCALayerプロパティをアニメートするには?

カスタムプロパティには、CALayerでaction(forKey:)を実装し、CAAnimationを返します。または、CADisplayLinkを使ったアニメーションで手動描画するためにCALayer.display()を使用します。CABasicAnimationをサポートするプロパティには、keyPathを文字列として指定するだけで協力できます。

アニメーションにCALayerがUIViewより効率的なのはなぜ?

CALayerはUIViewより軽いです: イベントハンドラ(touches、gestures)がなく、Auto Layoutに参加せず、アクセシビリティをサポートしません。ティピカルなCALayerは~100バイトですが、UIViewは~300+バイトです。Core Animationはメインスレッドをブロックせずに、GPU上のレンダサーバーでレイヤーを処理します。

まとめ

  • Core Animation — GPUレンダリングを伴うCALayerアニメーションのためのAppleのローレベルフレームワーク
  • CALayer — 60以上のアニメート可能なプロパティを持つベースクラス、CAShapeLayer、CAGradientLayer、CATextLayerをサポート
  • CABasicAnimation — fromValue/toValueによるシングルプロパティアニメーション、layer.add(animation, forKey:)で追加
  • CATransaction — 共通のduration、timingFunction、completionBlockでアニメーションをグループ化
  • インプリシットアニメーション — CALayerプロパティ変更による自動アニメーション(duration 0.25 s)
  • Presentation layer — アニメーション中の現在のレイヤー状態、中間値の読み取りに使用
  • パフォーマンス — ProMotionで最120 FPS、60 FPSで最1000レイヤー、4バイト/ピクセル

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください