Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails以外の開発一般

XcodeでリアルタイムにプレビューできるカスタムViewを作る

BPSの福岡拠点として一緒にお仕事をさせていただいています、株式会社ウイングドアのウメバヤシです。

XcodeのInterface Builder(以下、IB)でレイアウトを作成している時に、ちょっとボタンの角を丸くしたい時などに便利なカスタムViewの作り方を紹介します。

xibファイルなどでレイアウトとコードを作成して、それをStoryboardで利用する方法もありますが、今回はさくっとコードだけで実装する方法をとってみました。

IBDesignableとIBInspectable

カスタムViewを作る前にIBDesignableとIBInspectableについて説明しておきます。
この2つの機能はXcode6から使用できるようになっています。

BDesignableとは
クラス定義の前に「@IBDesignable」とつけることで、Viewプロパティの変更をIB上でリアルタイム反映させられる機能。
IBInspectableとは
"Viewのプロパティ値をIB上のAttributes Inspectorに表示させ、GUIで設定できるようにする機能。

UIViewの拡張

まず、IB上で通常は変更できないプロパティを設定できるようにするため、下記のコードでUIViewを拡張します。

プロパティ宣言の前に「@IBInspectable」とつけることで、IBからプロパティ値の変更が可能になります。

extension UIView {

    @IBInspectable
    var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
        }
    }

    @IBInspectable
    var borderWidth: CGFloat {
        get {
            return layer.borderWidth
        }
        set {
            layer.borderWidth = newValue
        }
    }

    @IBInspectable
    var borderColor: UIColor? {
        get {
            if let color = layer.borderColor {
                return UIColor(cgColor: color)
            }
            return nil
        }
        set {
            if let color = newValue {
                layer.borderColor = color.cgColor
            } else {
                layer.borderColor = nil
            }
        }
    }

    @IBInspectable
    var shadowRadius: CGFloat {
        get {
            return layer.shadowRadius
        }
        set {
            layer.shadowRadius = newValue
        }
    }

    @IBInspectable
    var shadowOpacity: Float {
        get {
            return layer.shadowOpacity
        }
        set {
            layer.shadowOpacity = newValue
        }
    }

    @IBInspectable
    var shadowOffset: CGSize {
        get {
            return layer.shadowOffset
        }
        set {
            layer.shadowOffset = newValue
        }
    }

    @IBInspectable
    var shadowColor: UIColor? {
        get {
            if let color = layer.shadowColor {
                return UIColor(cgColor: color)
            }
            return nil
        }
        set {
            if let color = newValue {
                layer.shadowColor = color.cgColor
            } else {
                layer.shadowColor = nil
            }
        }
    }
}

画像のようにAttributes Inspectorに項目が増えて設定できるようになります。
これだけではまだStoryboardには変更が反映されないので、次にIBDesignableを使って、リアルタイムで反映されるようにします。

カスタムViewを作る

今回は一例として、UIViewを継承したカスタムViewを作ってみます。
下記コードで@IBDesignable属性をつけた「DesignableView」クラスを作成します。

@IBDesignable
class DesignableView: UIView {
    // コードから生成したときに通る初期化処理
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setupAttributes()
    }

    // InterfaceBulderで配置した場合に通る初期化処理
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setupAttributes()
    }

    private func setupAttributes() {
        // 角の半径の初期値
        self.cornerRadius = 6.0
    }
}

IBでCustom Classを設定する

StoryboardでUIViewを配置し、Custom Classに先ほど作成したDesignableViewを設定します。

すると、角半径の初期値の6.0がデザイナーに反映され、Viewの見た目が変わったと思います。
※画像では見えやすいようにViewの背景だけ色を変えています。

IBInspectableで設定したプロパティについてもAttributes Inspectorで設定できるようになっています。

試しに上の画像のような設定にしてみると、こんな感じになります↓↓↓

実はこれ、User Defined Runtime Attributesという項目に設定を追加しているだけで、IBInspectableで拡張しなくても設定できるのですが、ひとつひとつ追加するのが面倒なので、拡張しておけば簡単に設定できます。

こんな感じでさくっとちょっとリッチなレイアウトが作成できるようになりました😊

ちなみに、UIViewを拡張したので、UIViewを継承した他の標準パーツもプロパティが増えていると思います。

まとめ

IBDesignableとIBInspectableを使って簡単にカスタムできるViewを作ってみました。

プロダクトの中でViewのレイアウトを統一させたいような時も、カスタムクラスで初期値を設定しておけば、後々の変更にも強い実装になるのでおすすめです。
ただXcodeのIBでは、プロパティを変更した際に自動でレンダリングが走るので、PCスペックによってはこの処理が若干重くなってしまいます。。
気になる方はメニューから「Editor」-「Automatically Refresh Views」のチェックを外し、自動レンダリング機能をオフしておくといいかもしれません。



株式会社ウイングドアでは、Ruby on RailsやPHPを活用したwebサービス、webサイト制作を中心に、
スマホアプリや業務系システムなど様々なシステム開発を承っています。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。