@IBDesignable 视图不会在 Interface Builder 中绘制背景颜色

@IBDesignable view doesn't draw background color inside Interface Builder

我很好奇为什么不将 backgroundColor 设置为红色?

@IBDesignable class CustomLabel: UIView {

  let view = UIView()

  func setup() {
    backgroundColor = UIColor.red
    view.backgroundColor = UIColor.green
    view.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
    addSubview(view)
  }

  override init(frame: CGRect) {
    super.init(frame: frame)
    setup()
  }
  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    setup()
  }
}

这是结果。

这就是我期望的样子。

在 Interface builder(IB) 中呈现时,在调用 init 后加载自定义 UI 元素的 IB 中设置的属性。正在调用您在 init 中设置 backgroundColor 的代码。但在那之后,它再次为 IB.

中的 backgroundColor 的值设置 backgroundColor

我找不到这方面的 Apple 文档。我这样说是基于以下分析。为了调试,我稍微修改了你的代码。

@IBDesignable class CustomLabel: UIView {

    let view = UIView()

    override var backgroundColor: UIColor? {
        didSet {
            print("here: "); // break point 1
        }
    }

    func setup() {
        self.backgroundColor = UIColor.redColor()  // break point 2
        view.backgroundColor = UIColor.greenColor()
        view.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
        addSubview(view)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)  // break point 3
        setup()
    }
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)  // break point 4
        setup()
    }
}

现在,将断点放在所有方法中。然后,在 Interface Builder 中 select CustomLabel 的对象,然后选择 Editor ➔ Debug Selected Views。

您可以看到方法调用的顺序。这只是显示了界面生成器中的渲染顺序,而不是它在 运行 时间内可能遵循的顺序。

可能您知道这一点,但为了清楚起见,您可以使用以下方式在 IB 中反映这一点。

override func prepareForInterfaceBuilder() {
    super.prepareForInterfaceBuilder()
    backgroundColor = UIColor.grayColor()

}

init(frame:)和init?(coder:)的逻辑在InterfaceBuilder渲染模式下会产生两种不同的渲染,因为IBDesignablesAgent-iOS用来渲染IBDesignable的类调用了init(frame :) 然后它使用“用户定义的 运行 时间属性”默认/自定义值来配置自定义视图。因此,在 init(frame:) 中设置的 backgroundColor 将被 Interface builder 中设置的背景颜色值 default/custom 更改。 如果应用 运行 在设备或模拟器上呈现 运行 时间,则使用 init?(coder:) 方法并在故事板的默认/自定义值之后应用“setup()”逻辑被应用。如果从代码创建自定义视图,则使用 init(frame:) 方法,但故事板的“用户定义 运行 时间属性”没有解码,因为这个不存在。