私が何について話しているのかわからない人のために、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を描画できますか?
この質問を投稿してから、@ IBDesignableはクラス拡張では機能しないことを学びました。タグを追加することはできますが、効果はありません。
以下のコードで動作させることができましたが、副作用として、ストーリーボードの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
}
}
@IBDesignableは、カスタムクラスでのみUIView拡張機能を使用できます。たとえば。 UILabelは、UIViewのデフォルトのサブクラスです。そこでは機能しませんが、MyUILabelというカスタムクラスを作成してUILabelをサブクラス化するとします。作業中のラベルにMyUILabelクラスを割り当てます。次に、UIView拡張機能のコーナー半径がこのMyUILabelで機能します。 (最初の1週間は、カスタムクラスを扱っているためだと思います。)