UIViewとCALayerの階層構造


UIViewとCALayerを複数重ねたときの順番でハマったのでメモ。

UIViewとCALayerを用意する

ViewController.swift
import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let viewA = UIView()
        viewA.frame = CGRect(x: 30, y: 100, width: 100, height: 100)
        viewA.backgroundColor = UIColor.blue

        let viewB = UIView()
        viewB.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
        viewB.backgroundColor = UIColor.red

        let viewC = UIView()
        viewC.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
        viewC.backgroundColor = UIColor.green

        let layerA = CALayer()
        layerA.frame = CGRect(x: 10, y: 10, width: 80, height: 80)
        layerA.backgroundColor = UIColor.yellow.cgColor

        let layerB = CALayer()
        layerB.frame = CGRect(x: 10, y: 10, width: 80, height: 80)
        layerB.backgroundColor = UIColor.purple.cgColor

        let layerC = CALayer()
        layerC.frame = CGRect(x: 10, y: 10, width: 80, height: 80)
        layerC.backgroundColor = UIColor.brown.cgColor

        /*
         * todo: ここを後述のコードで置き換える
         */
    }
}

CALayer → UIView の順で追加

先に各UIViewにCALayerを追加しておくパターン。

viewA.layer.addSublayer(layerA)
viewB.layer.addSublayer(layerB)
viewC.layer.addSublayer(layerC)

view.addSubview(viewA)
viewA.addSubview(viewB)
viewB.addSubview(viewC)

UIView → CALayer の順で追加

先にUIViewを重ねて、その後にCALayerを追加するパターン

view.addSubview(viewA)
viewA.addSubview(viewB)
viewB.addSubview(viewC)

viewA.layer.addSublayer(layerA)
viewB.layer.addSublayer(layerB)
viewC.layer.addSublayer(layerC)

実行結果

CALayer → UIView UIView → CALayer

両方とも同じ結果になると思っていたので、Viewがうまく表示されずハマってしまった。
Debug View Hierarchyで確認するとどちらの実装も同じ表示だった。

まとめ

UIViewとCALayerは追加した順に表示されるっぽい