【问题标题】:Can you add IBDesignable properties to UIView using categories/extensions?您可以使用类别/扩展将 IBDesignable 属性添加到 UIView 吗?
【发布时间】:2015-07-06 13:29:28
【问题描述】:

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

当您使用 IBInspectable 属性标记自定义视图时,这些属性会显示在 IB 的 Attributes Inspector 中。

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

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

我在 Objective-C 中创建了 UIView 类别,并在 Swift 中创建了 UIView 的扩展,将视图底层的borderWidth、cornerRadius、borderColor 和layerBackgroundColor 属性提升为视图的属性。如果更改属性,扩展/类别会根据需要进行类型转换并将更改转发到图层。

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

上周我可以发誓,我的视图类别/扩展上的 IBDesignable 属性也在工作,我可以看到我的自定义 UIView 类别在 IB 中呈现,它的图层属性已更改。这周它不工作。

我是不是产生了幻觉?

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

【问题讨论】:

  • 是的,你可以...我相信。哪个部分不工作?您不能在属性检查器中设置属性?或者您可以在检查器中设置它们,但视图不会更新以反映更改?
  • 嗯,我收回了。看起来我能够让属性显示在属性检查器中,但它们不会在界面生成器上更新。但是,如果我编译并运行,属性 被应用
  • @nhgrif,我应该更清楚。这是正确的。属性显示在检查器中,我可以设置它们的值,然后它们在正在运行的程序中工作。但是该视图并未反映 IB 窗口中的更改。
  • IBDesignable 确实适用于自定义子类。看起来它不适用于类别/扩展,即使我可以发誓它上周工作。我想知道 Xcode 的最新更新是否破坏了它?
  • "Is it possible" 不适合 Stack Overflow。除了“是”或“否”之外,您如何回答“有可能”的问题?同时,“我如何”问题回答您的“是否可能”,并鼓励实际展示其完成方式的答案(这也是您真正想要的)。见thisthis

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


【解决方案1】:

自从发布这个问题后,我了解到@IBDesignable 不适用于类扩展。您可以添加标签,但它没有效果。

【讨论】:

  • 作品:pod 'UIView-IBDesignable'
  • 不,它 dont. Ive 刚刚测试过。左视图是 UIView 的子类,右视图是纯 UIView。它们具有相同的属性。 imgur.com/a/o5Dwn仍在寻找决定
  • 像魅力一样为我工作。但是,我注意到这个 UIView 扩展库不适用于独立的 UIView - 它仅适用于 UIView 的子类。不理想。 @Dren 你能在 UIView 的子类上再试一次并确认它是否有效吗?
  • @avishic,请勿编辑某人的答案以改变答案的含义。如果您不同意该答案,请发表评论,或以另一种观点发表其他答案。 IBDesignable 适用于子类,但不适用于扩展。如果您有相反的具体信息,请通过具体示例发布您自己的答案。
  • @DuncanC,对不起,没问题。
【解决方案2】:

我能够使用下面的代码使其工作,但副作用是有时故事板中的 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】:

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

    【讨论】:

      【解决方案4】:

      我通过将一个@IBDesignable UIView 设置为我的视图控制器中的顶视图,为我的用例完成了这项工作。我的特殊用例是让 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
          }
      }
      

      【讨论】:

      • 叹息,看起来 IB 没有在不可设计的类上设置运行时属性,这可能会让我无法使用它。最初,一切似乎都在我的用例中正常工作,但我只是在视图类上使用选择器测试样式表,而不是特定样式——这取决于是否具有运行时属性。
      【解决方案5】:

      这个代码块很适合我。

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

      注意从框架导入时可能无法正常工作。我现在正试图找出原因。

      【讨论】:

      • 这就是你问题的答案吗,邓肯?
      • 这个答案显示@IBInspectable OP 已经声明他工作正常。他专门询问@IBDesignable
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 2021-06-18
      相关资源
      最近更新 更多