iosswiftinterface-builderibdesignable

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


I'm curious why doesn't this set the backgroundColor to red?

@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()
  }
}

This is the result.

enter image description here

And this is what I expect it to look like.

enter image description here


Solution

  • While rendering in Interface builder(IB), the properties which are set in IB of custom UI element are loaded after the call to init. Your code for setting the backgroundColor in init is getting called. But after that, it again sets the backgroundColor for the value of backgroundColor in IB.

    I could not find the Apple documentation for this. I am saying this based on following analysis. I modified your code a little for debugging.

    @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()
        }
    }
    

    Now, put the breakpoints in all methods. Then, select the object of CustomLabel in Interface Builder, and choose Editor ➔ Debug Selected Views.

    You can see the sequence of method calls. This just shows the sequence of rendering in interface builder, not the sequence it may follow in run time.

    May be you know this, but for the sake of clarity, you can use following to reflect this in IB.

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