web-dev-qa-db-ja.com

カテゴリ/拡張機能を使用して、IBDesignableプロパティをUIViewに追加できますか?

私が何について話しているのかわからない人のために、Xcode6.0は新しい機能IBDesignableとIBInspectableを追加しました。

カスタムビューにIBInspectableプロパティのタグを付けると、それらのプロパティはIBの属性インスペクターに表示されます。

同様に、カスタムUIViewサブクラスにIBDesignableのタグを付けると、Xcodeはビューをコンパイルし、コードを呼び出してビューオブジェクトをXcodeウィンドウに直接レンダリングし、それらがどのように見えるかを確認できるようにします。

IBDesignable属性とIBInspectable属性をカスタムビューに追加する手法は、SwiftとObjective-Cでほぼ同じです。IBInspectableプロパティは、定義に使用する言語に関係なく、InterfaceBuilder属性インスペクターに表示されます。

Objective-CでUIViewのカテゴリを作成し、SwiftでUIViewの拡張機能を作成しました。これにより、ビューの基になるレイヤーのborderWidth、cornerRadius、borderColor、layerBackgroundColorプロパティがビューのプロパティとしてプロモートされます。 。プロパティを変更すると、拡張機能/カテゴリは必要に応じて型変換を行い、変更をレイヤーに転送します。

IBInspectable部分はうまく機能します。 IB属性インスペクターで新しいプロパティを確認して設定できます。

先週、ビューカテゴリ/拡張機能のIBDesignable属性も機能しており、レイヤー属性が変更されたIBでカスタムUIViewカテゴリがレンダリングされていることを誓うことができました。今週は機能していません。

私は幻覚でしたか?

既存のシステムクラスのカテゴリ/拡張機能は、IBDesignableで設定されている場合、Interface BuilderでカスタムUIを描画できますか?

17
Duncan C

この質問を投稿してから、@ IBDesignableはクラス拡張では機能しないことを学びました。タグを追加することはできますが、効果はありません。

25
Duncan C

以下のコードで動作させることができましたが、副作用として、ストーリーボードのIBエージェントが、更新する必要のあるUI要素が多すぎるためにクラッシュすることがあります。 Xcodeを再起動すると、次のクラッシュまで一時的に問題が修正されます。多分それはOPが直面している問題です

@IBDesignable
extension UIView
{

    @IBInspectable
    public var cornerRadius: CGFloat
    {
        set (radius) {
            self.layer.cornerRadius = radius
            self.layer.masksToBounds = radius > 0
        }

        get {
            return self.layer.cornerRadius
        }
    }

    @IBInspectable
    public var borderWidth: CGFloat
    {
        set (borderWidth) {
            self.layer.borderWidth = borderWidth
        }

        get {
            return self.layer.borderWidth
        }
    }

    @IBInspectable
    public var borderColor:UIColor?
    {
        set (color) {
            self.layer.borderColor = color?.cgColor
        }

        get {
            if let color = self.layer.borderColor
            {
                return UIColor(cgColor: color)
            } else {
                return nil
            }
        }
    }
}

そのため、この機能を拡張する必要があるサブクラスを減らすためにwhere句を追加しようとしています: 汎用IBDesginables UIView拡張

ビューコントローラのトップビューとして設定した@IBDesignableUIViewを1つ持つことで、このユースケースでこれを機能させました。私の特定のユースケースは、ClassyKitのスタイルをデフォルトのUIKitビューのInterface Builderで表示できるようにすることです。そのためだけにサブクラスを作成する必要はなく、うまく機能しています。

設定方法の例を次に示します。

// in Interface Builder set the class of your top view controller view to this
@IBDesignable class DesignableView: UIView {
}

extension UIView {
    open override func prepareForInterfaceBuilder() {
        subviews.forEach {
            $0.prepareForInterfaceBuilder()
        }
    }
}

extension UILabel {
// just an example of doing something
    open override func prepareForInterfaceBuilder() {
        layer.cornerRadius = 8
        layer.masksToBounds = true
        backgroundColor = .red
        textColor = .green
    }
}
1
Richard Burgess

@IBDesignableは、カスタムクラスでのみUIView拡張機能を使用できます。たとえば。 UILabelは、UIViewのデフォルトのサブクラスです。そこでは機能しませんが、MyUILabelというカスタムクラスを作成してUILabelをサブクラス化するとします。作業中のラベルにMyUILabelクラスを割り当てます。次に、UIView拡張機能のコーナー半径がこのMyUILabelで機能します。 (最初の1週間は、カスタムクラスを扱っているためだと思います。)

1
Lawrence Cheuk