Search code examples
iosxcodeinterface-builderibdesignable

xcode Interface Builder not updating IBDesignable class


In my project, I have several custom class files based on UITextField and UIButton.

As an example, the UITextField class looks like this:

import UIKit

@IBDesignable class RoundedTextField: UITextField {

    override func awakeFromNib() {
        super.awakeFromNib()

        layer.cornerRadius = 25
        layer.borderWidth = 2
        layer.borderColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
        clipsToBounds = true
        textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

        // Placeholder colour
        attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: [NSAttributedStringKey.foregroundColor: #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)])
    }

    // Placeholder text indent
    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: 20, dy: 5)
    }

    // Editing text indent
    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: 20, dy: 5)
    }
}

Here is the correct version that the simulator shows me: SimScreenshot

Here is what IB shows me: IBScreenshot

As you can see from my IB screenshot, the only element that updates is the indentation of the placeholder text. The rest of the customisation from the class is not updating.

Any thoughts?

P.s. when I select an element, in the identity inspector, the 'Designables' field is "Up to date".

I have tried cleaning, building and restarting Xcode.

Thanks! Scott


Solution

  • I solved the issue with help from Reinier's 2nd link and a course I previously took on Udemy.

    I implemented my customisation in a setupView() function. I called this in prepareForInterfaceBuilder() and also awakeFromNib()

    import UIKit
    
    @IBDesignable class RoundedTextField: UITextField {
    
        override func awakeFromNib() {
            super.awakeFromNib()
            setupView()
        }
    
        override func prepareForInterfaceBuilder() {
            super.prepareForInterfaceBuilder()
            self.setupView()
        }
    
        // Placeholder text indent
        override func textRect(forBounds bounds: CGRect) -> CGRect {
            return bounds.insetBy(dx: 20, dy: 5)
        }
    
        // Editing text indent
        override func editingRect(forBounds bounds: CGRect) -> CGRect {
            return bounds.insetBy(dx: 20, dy: 5)
        }
    
        func setupView() {
            layer.cornerRadius = 25
            layer.borderWidth = 2
            layer.borderColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
            clipsToBounds = true
            textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
    
            // Placeholder colour
            attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: [NSAttributedStringKey.foregroundColor: #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)])
        }
    }