【Swift】CALayerクラスとは?UIVewとの違いとアニメーションの実装

この記事からわかること

  • SwiftCALayerクラスとは?
  • Core Animationフレームワーク役割
  • UIViewとの違い
  • レイヤー実装方法

index

[open]

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

みんなの誕生日

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

posted withアプリーチ

CALayerクラスならびにCore Animationフレームワークについて気になったのでリファレンスを読んでまとめてみました。至らぬ点や誤った理解があれば教えていただけると嬉しいです。

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(レイヤーオブジェクト)です。

CALayerクラスとは?

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

CALayerクラスはコンテンツを表示するための機能を提供するオブジェクトです。レイヤーとは日本語で「」を意味する英単語です。

このレイヤーオブジェクトがコンテンツやジオメトリ(形状)、視覚的属性情報などBitmap形式のために必要な情報を管理します。ビューと似たような特徴を持っているため混同しがちですがあくまで情報だけを管理しておりモデルとして位置付けされており、ビューとは異なり独自の外観は定義しません。

※ジオメトリとは描画対象を表す座標や長さなどの情報のこと。

使われている場所

iOS(UIKit)では実際にCALayerオブジェクトはUIViewクラスと紐づいています。UIViewにはCALayer型のlayerプロパティが用意され、1つのビューオブジェクトに対してレイヤーオブジェクトが自動で生成されるようになっています。これを「 レイヤーバックビュー(layer-backed-view)」と呼びます。

var layer: CALayer { get }

またUIViewはCALayerをラップしているため描画を操作すると相互に影響しあいます。

view. backgroundColor = .red
print(view.layer.backgroundColor) // Optional(<CGColor 0x6000028e8000> [<CGColorSpace 0x6000028f8a20> (kCGColorSpaceICCBased; kCGColorSpaceModelRGB; sRGB IEC61966-2.1; extended range)] ( 1 0 0 1 ))

どちらも描画に関するクラスですが、両者の役割は異なります。

UIView・・・描画やイベント処理などを担当

CALayer・・・描画する内容(画像情報)を管理

役割は異なりますが階層構造で管理される点は同じです。CALayerもUIView同様にスーパーレイヤー(親)とサブレイヤー(子)の関係を持つ階層構造で管理されています。

【Swift/UIKit】UIViewControllerの役割とは?ビュー階層とviewDidLoadメソッド

おすすめ記事:【Swift/UIKit】UIViewクラスとは?使い方やプロパティまとめ

アンダーライングレイヤーとスタンドアロンレイヤー

階層構造で管理されているためスーパーレイヤー(親)の配下にサブレイヤー(子)を追加できることがわかりました。追加するためには新しくレイヤーオブジェクトを生成し、addSublayerメソッドを使って追加します。

最初からviewに対応したlayerを「アンダーライングレイヤー(underlying layer)」と呼び、個別に新しく生成しまだビューと紐づいていないレイヤーを「スタンドアロンレイヤー(standalone layer)」と呼びます。

view.layer // アンダーライングレイヤー
let myLayer = CALayer() // スタンドアロンレイヤー

用語まとめ

実際にレイヤーを追加してみる

実際にレイヤーを追加してみます。紐付けたUIViewを用意して新しいレイヤーオブジェクト(スタンドアロンレイヤー)を生成し、ルートレイヤーの配下に追加してみます。

class ViewController: UIViewController {
  
  @IBOutlet  weak var rootView: UIView!
  
  override func viewDidLoad() {
      super.viewDidLoad()
      
      let newLayer = CALayer()
      newLayer.backgroundColor = UIColor.orange.cgColor
      newLayer.anchorPoint = view.center
      newLayer.frame = CGRect(x: view.center.x - 40 , y: view.center.y - 40 , width: 80, height: 80)
      newLayer.opacity = 0.8
      newLayer.cornerRadius = 5
      rootView.layer.addSublayer(newLayer)
  }
}
【Swift】CALayerクラスとは?UIVewとの違いとアニメーションの実装

今回は中心に少しだけ透過させて角を丸くした四角形を表示してみました。カラーを指定する際はUIColorではなくCGColorになるので注意してください。ちなみにCGは「Core Graphics」の略称です。

おすすめ記事:【Swift】CGRectの使い方!Core Graphicsとは?

レイヤー階層の操作

レイヤー階層は追加/挿入/削除/交換などの操作が可能になっています。先ほどは追加(addSublayer)の例です。

用意されているメソッド

メソッド 概要
addSublayer 追加
insertSublayer:above:
insertSublayer:atIndex:
insertSublayer:below:
挿入
removeFromSuperlayer 削除
replaceSublayer:with: 交換

またレイヤーに対して回転や透明度の設定など何かしら変更をするとサブレイヤーにも影響を与えます。

アニメーションを実装してみる

追加したレイヤーに「ボタンクリックで透明度を変換させる」アニメーションを実装してみたいと思います。

class ViewController: UIViewController {
    
    @IBOutlet  weak var rootView: UIView!
    var newLayer:CALayer = CALayer()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        newLayer.backgroundColor = UIColor.orange.cgColor
        newLayer.anchorPoint = view.center
        newLayer.frame = CGRect(x: view.center.x - 40 , y: view.center.y - 40 , width: 80, height: 80)
        newLayer.cornerRadius = 5
        rootView.layer.addSublayer(newLayer)
    }
    
    @IBAction  func changeOpacity() {
        if  newLayer.opacity == 1.0 {
          // この変化でアニメーションが実装される
            newLayer.opacity = 0.1
        } else {
            newLayer.opacity = 1.0
        }
    }
}

追加したレイヤーの透明度(opacity)の値を変更するだけ滑らかにビューが変化するようになっているので試してみてください。

アニメーションが実行されない?

先ほどの感覚でアンダーライングレイヤーにもアニメーションを実装してみようとするとこちらはアニメーションが実行されずにパッと切り替わる変化になってしまいます。これはアンダーライングレイヤーの場合は内部的にアニメーションがオフになっているために起きてしまうようです。

class ViewController: UIViewController {
    
    var label: UILabel = UILabel()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        label.frame = CGRect(x: 0, y: 0, width: 200, height: 50)
        label.center = view.center
        label.backgroundColor = .brown
        label.layer.cornerRadius = 5
        label.clipsToBounds = true
        view.addSubview(label)
    }
    
    @IBAction  func changeOpacity() {
        if  label.layer.opacity == 1.0 {
          // この変化ではアニメーションが実装されない
            label.layer.opacity = 0.1
        } else {
            label.layer.opacity = 1.0
        }
    }
}

Core Animationでのより複雑なアニメーション実装は以下の記事を参考にしてください。

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

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

searchbox

スポンサー

ProFile

ame

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

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

New Article

index