您可以使用类别/扩展名向UIView添加IBDesignable属性吗?

时间:2015-04-27 22:08:15

标签: ios interface-builder xcode-storyboard ibdesignable ibinspectable

对于那些不知道我在说什么的人,Xcode 6.0增加了新功能,IBDesignable和IBInspectable。

使用IBInspectable属性标记自定义视图时,这些属性将显示在IB的“属性”检查器中。

同样,当您使用IBDesignable标记自定义UIView子类时,Xcode会编译您的视图并调用代码以在Xcode窗口中直接呈现视图对象,以便您可以看到它们的外观。

在Swift和Objective-C中,将IBDesignable和IBInspectable属性添加到自定义视图的技术非常相似。 IBInspectable属性出现在Interface Builder Attributes Inspector中,无论您使用哪种语言来定义它们。

我在Objective-C中创建了一个UIView类,并在Swift中创建了UIView的扩展,它将视图底层的borderWidth,cornerRadius,borderColor和layerBackgroundColor属性提升为视图的属性。如果更改属性,则扩展名/类别会根据需要键入转换,并将更改转发给图层。

IBInspectable部分效果很好。我看到并可以在IB属性检查器中设置新属性。

上周我可以发誓,我的视图类别/扩展名上的IBDesignable属性也正常工作,我可以在IB中看到我的自定义UIView类别渲染,其中包含更改的图层属性。本周它无法正常工作。

我是产生幻觉的吗?

现有系统类的类别/扩展可以在使用IBDesignable设置时在Interface Builder中绘制自定义UI吗?

5 个答案:

答案 0 :(得分:23)

自发布此问题以来,我了解到@IBDesignable不适用于类扩展。您可以添加标记,但它没有任何效果。

答案 1 :(得分:1)

@IBDesignable仅在自定义类中使用UIView扩展。例如。 UILabel是UIView的默认子类。它不会在那里工作,但如果你创建一个名为MyUILabel的自定义类,则继承UILabel。将MyUILabel类分配给您正在处理的Label。那么你在UIView扩展中的角半径将适用于这个MyUILabel。  (我想它适用于你的第一周是因为你正在处理一些自定义类。)

答案 2 :(得分:1)

我能够使用下面的代码,但副作用是有时候故事板中的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 子句来减少应该扩展此功能的子类的原因: Generic IBDesginables UIView extension

答案 3 :(得分:0)

我通过在视图控制器中设置了一个@IBDesignable UIView作为顶视图,为我的用例做了这项工作。我的特殊用例是在默认的UIKit视图中在Interface Builder中显示ClassyKit样式,而不必为此子类化它并且它工作得很好。

以下是您如何设置的示例:

// 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
    }
}

答案 4 :(得分:-4)

此代码块对我来说效果很好。

import UIKit

public extension UIView {
    @IBInspectable public var cornerRadius: CGFloat {
        get {
            return layer.cornerRadius
        }
        set {
            layer.cornerRadius = newValue
            layer.masksToBounds = newValue > 0
        }
    }
}

注意从框架导入时可能无效。我现在试图找出原因。