iOSエンジニアのつぶやき

毎朝8:30に iOS 関連の技術について1つぶやいています。まれに釣りについてつぶやく可能性があります。

Attributes Inspector でカスタムプロパティを指定できるようにする

今回は、Storyboard や xib などの Interface Builder を使ってレイアウトを設計する際などに知っておくと少し便利な、@IBDesignable・@IBInspectable について簡単にまとめていこうかと思います。

f:id:yum_fishing:20201003204610p:plain

@IBDesignable とは?

Storyboard や xib などの Interface Builder で、コードまたはカスタムインスペクターによる変更を元にレイアウトをライブレダンリングできるようにするためのアノテーションで、Xcode6以降から利用できるようになったそうです。

実際に使用した例が下記のようになります。prepareForInterfaceBuilder は、designable object が Inteface Builder で作成された時に、生成されます(厳密には ViewClass に designable object が指定された時に呼び出される)。下記のようにすることで、設定したプロパティなどが変更された際に prepareForInterfaceBuilder() が呼び出され、レイアウトがライブレンダリングされます。基本的には、Inteface Builder がこのメソッド呼び出すので、システムから呼ばれることはありません。

@IBDesignable class TestView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    // MARK: - UI Setup
    override func prepareForInterfaceBuilder() {
        self.backgroundColor = color
        self.layer.cornerRadius = cornerRadius
        self.layer.borderWidth = borderWidth
        self.layer.borderColor = borderColor.cgColor
    }

    // MARK: - Properties
    var color: UIColor = .red {
        didSet {
            self.backgroundColor = color
        }
    }
    
    var cornerRadius: CGFloat = 40 {
        didSet {
            self.layer.cornerRadius = cornerRadius
        }
    }

    var borderWidth: CGFloat = 10 {
        didSet {
            self.layer.borderWidth = borderWidth
        }
    }
    
    var borderColor: UIColor = .black {
        didSet {
            self.layer.borderColor = borderColor.cgColor
        }
    }
}

また、mata,required init?(coder: NSCoder) のみ実装していると下記のような Error が出るので、override init(frame: CGRect) も実装します。

IB Designables: Failed to render and update auto layout status

@IBInspectable とは?

Storyboard や xib で指定することのできる、attributes をコードで作成できるようにするためのアノテーションです。これにより、指定されたプロパティは、attributes inspector に表示され、Inteface Builder から値を変更できるようになります。また、@IBInspectable に指定できる型には決まりがあり下記のようなものが利用可能です。

先ほどのコードを下記のように修正すると attributes inspector から、それぞれ @IBInspectable アノテーションがついがプロパティを操作できるようになります。

@IBDesignable class TestView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }

    // MARK: - UI Setup
    override func prepareForInterfaceBuilder() {
        self.backgroundColor = color
        self.layer.cornerRadius = cornerRadius
        self.layer.borderWidth = borderWidth
        self.layer.borderColor = borderColor.cgColor
    }

    // MARK: - Properties
    @IBInspectable var color: UIColor = .red {
        didSet {
            self.backgroundColor = color
        }
    }

    @IBInspectable var cornerRadius: CGFloat = 40 {
        didSet {
            self.layer.cornerRadius = cornerRadius
        }
    }

    @IBInspectable var borderWidth: CGFloat = 10 {
        didSet {
            self.layer.borderWidth = borderWidth
        }
    }

    @IBInspectable var borderColor: UIColor = .black {
        didSet {
            self.layer.borderColor = borderColor.cgColor
        }
    }
}

また、enum を操作できるようにしたいところですが、enumObjective-C でサポートされていないため、下記のような Error をはかれます。

    enum Hoge {
        case a
        case b
    }

    @IBInspectable var hoge: Hoge = .a
Property cannot be marked @IBInspectable because its type cannot be represented in Objective-C

下記のようにして、Error を退避することも可能ですが、IB は Objective-C でも enum をサポートしていないため、今度は attributes inspector に表示されなくなります😅

    @objc enum Hoge: Int {
        case a
        case b
    }

    @IBInspectable var hoge: Hoge = .a

参考

その他の記事

yamato8010.hatenablog.com

yamato8010.hatenablog.com

yamato8010.hatenablog.com