[iOS] CALayerを使ってグラフィック操作で遊んでみよう!

こんにちは。きんくまです。

最近のiOSアプリ開発は、どちらかというと本格的なツールアプリが多く、グラフィック操作で遊んでみることもあまりないかと思います。

それで、せっかくなので、あんまりやらなくなったグラフィック操作で遊んでみよう!というのが今回の記事になります。

今回作ったもの

ボタンを押すと、半透明のタイルが追加されていきます。

CALayerって何?

UIViewには、layerというプロパティがあります。

layer - UIView | Apple Developer Documentation

みていただくとわかる通り型はCALayer型になっています。UIViewはデフォルトでCALayer型のlayerをひとつだけもっています。
UIViewはaddSubViewをすることで、階層構造をもたせてViewを配置することが可能です。
それと同じように、CALayerもaddSubLayerをすることで、階層構造をもたせてLayerを配置することが可能です。
ひとつのUIViewのlayerに複数のCALayerを吊るしていくことができます。

じゃあ、なんでCALayerを使うかというと、描画が軽い。これに尽きます。
CALayerはUIViewと違って、touchesBeganなどのタッチイベントを受け取ることができません。そういったものを無くしてあり、描画に特化しているので、描画を素早く行うことが可能です。

ちなみにCAはCoreAnimationの略です。
Core Animation | Apple Developer Documentation

CALayerのサブクラスってどんなのがあるの?

UIViewのサブクラスにUITextViewやUILabelがあるように、CALayerのサブクラスもいろいろあります。

参考)
CALayer Tutorial for iOS: Getting Started | raywenderlich.com

上のページをみていただくとわかると思いますが、いろいろとあります。

デモを作る

いろいろとあるのですが、今回はCALayerだけを使って簡単なデモを作ります。
最終的な制作物は、最初にお見せしたYoutubeの動画のやつになります。

ランダムな色を作る

追加されるCALayerの色をランダムで変えたいので、まずはランダムな色を作ってみましょう

    func generateRandomColor() -> UIColor {
        let hue = Float.random(in: 0 ... 1.0)
        let saturation = Float.random(in: 0 ... 1.0)
        let brightness = Float.random(in: 0 ... 1.0)
        return UIColor(hue: CGFloat(hue),
                       saturation: CGFloat(saturation),
                       brightness: CGFloat(brightness),
                       alpha: 0.25)
    }

色指定の方法なのですが、こういう時は、RGBではなく HSB形式の方が扱いやすいです。

  • H: Hue 色相
  • S: Saturation 彩度
  • B: Brightness 明るさ

となります。上のコードの例ではHSB全てが0〜1の値をとります。

この状態だとどんな感じになるのでしょうか?

色が全くのランダムのため、絵の具を混ぜ合わせたような感じになりました。

ここでためしに、色相を少し絞ってみましょう。

値が 0.3 から 0.5 のときは緑の色相にしぼられます。

let hue = Float.random(in: 0.3 ... 0.5)

値が 0.7 から 0.9 のときは紫の色相にしぼられます。

let hue = Float.random(in: 0.7 ... 0.9)

おなじような感じで、Saturationを調整すれば、鮮やかさが設定できます。また、Brightnessを調整すれば、明るさが設定できます。

こんな感じに、ランダム性を持ちつつ、「紫系で、鮮やかで、暗い色」という感じに絞り込むことが可能です。

色のついたCALayerを作る

さきほどのランダム色を利用してCALayerを作成します。

    func createColoredLayer(width: CGFloat = 50.0, height: CGFloat = 50.0) -> CALayer {
        let newLayer = CALayer()
        newLayer.backgroundColor = generateRandomColor().cgColor
        newLayer.anchorPoint = CGPoint(x: 0, y: 0)
        newLayer.frame = CGRect(x: 0, y: 0, width: width, height: height)
        return newLayer
    }

ちょっと気をつけないといけないところは、色指定だったり、座標の指定の型が全て CGColorやCGPointなどCGで始まるというところです。
このCGはCoreGraphicsの略になります。
Core Graphics | Apple Developer Documentation

ランダム座標にCALayerを追加する

ここまでできたら、CALayerのXY座標をランダムにして貼り付けるだけです。
今回は貼り付け先のUIViewからはみ出さないように、CALayerの幅と高さの分だけ調整して、ランダム座標を求めました。

    @IBOutlet weak var canvasView: UIView!
    
    var canvasLayer: CALayer {
        return canvasView.layer
    }
    
    @IBAction func addLayerButtonTapped() {
        addRandomColoredLayer()
    }
    
    func addRandomColoredLayer() {
        let layerSize = CGSize(width: 100, height: 100)
        let coloredLayer = createColoredLayer(width: layerSize.width, height: layerSize.height)
        let maxX: Float = Float(canvasView.frame.width - layerSize.width)
        let randomX = Float.random(in: 0 ... maxX)
        let maxY: Float = Float(canvasView.frame.height - layerSize.height)
        let randomY = Float.random(in: 0 ... maxY)
        coloredLayer.position = CGPoint(x: CGFloat(randomX), y: CGFloat(randomY))
        canvasLayer.addSublayer(coloredLayer)
    }

最終的なソース

cm-tsmaeda/CALayerSample

まとめ

今回は、CALayerだけを使って、色のついたレイヤーをランダムで追加するというのをやってみました。

実は今回のCALayerの話は、以前に読んだ本を思い出して書いています。(10年前w)

Core Animation for Mac OS X and the iPhone: Creating Compelling Dynamic User Interfaces (Pragmatic Programmers)

まだ家にあるかどうかわからないのですが、CABasicAnimationを使ってアニメーションさせるとかそういうのも載っていたはず。
あとランダム色やランダム座標の話とかは、昔やってたFlash時代に勉強したものになります。

今回はパスを使って図形を描画するとかをやっていないので、そのうちやってみたいと思います。
ではでは。