Search code examples
swiftuitextfielduiswitch

How to properly set TextField's background color and text color in Swift


Please don't mark as duplicate because I seem to have a bug where the usual code doesn't work. I went through all the available threads but haven't found a solution.

I have the following cell:

enter image description here

When the UISwitch is turned off, I want the UITextField to be dark and text color bright. When turned on the opposite to simulate a "disable" behavior.

My code:

func setTextFieldActivation(isOn: Bool) {

    self.theTextField.isUserInteractionEnabled = isOn

    self.theTextField.set(

        bgColor: isOn ? Colors.moreLightGrey : Colors.leastLightGray, //Colors is a global struct of UIColor to cache reused colors
        placeholderTxt: String(),
        placeholderColor: isOn ? Colors.black : Colors.white,
        txtColor: isOn ? Colors.black : Colors.white
    )
}

The extension set

extension UITextField {


    func set(bgColor: UIColor, placeholderTxt: String, placeholderColor: UIColor, txtColor: UIColor) {

        self.backgroundColor = bgColor
        self.attributedPlaceholder = NSAttributedString(string: placeholderTxt, attributes: [NSForegroundColorAttributeName: placeholderColor])
        self.textColor = txtColor
    }
}

The issue: When I turn on the UISwitch, the background color changes as wanted but the text color remains.

enter image description here

The weird part: When I click the UITextField and it becomes first responder, the text color changes to what I want.

enter image description here

But when I turn the Switch off again, the color remains dark.

enter image description here

What am I missing? Help is very appreciated.

PS: Xcode 9, Swift 3.

The code is called whenever the switch is changed:

self.theSwitch.addTarget(self, action: #selector(switchChanged), for: .valueChanged)

func switchChanged(mySwitch: UISwitch) {

    self.setTextFieldActivation(isOn: mySwitch.isOn)
}

Solution

  • I think I figured it out. The wired thing is that the textColor is not updated until layoutSubviews(). I tried two approaches which seem to solve the problem.

    The first approach is to call layoutSubviews() directly at the end of the set method

    func set(bgColor: UIColor, placeholderTxt: String, placeholderColor: UIColor, txtColor: UIColor) {
    
        backgroundColor = bgColor
        attributedPlaceholder = NSAttributedString(string: placeholderTxt, attributes: [NSForegroundColorAttributeName: placeholderColor])
        textColor = txtColor
    
        layoutSubviews()
    }
    

    The second approach is to set the text for the UITextField to it's current value which will trigger layoutSubviews() as well.

    func set(bgColor: UIColor, placeholderTxt: String, placeholderColor: UIColor, txtColor: UIColor) {
    
        backgroundColor = bgColor
        attributedPlaceholder = NSAttributedString(string: placeholderTxt, attributes: [NSForegroundColorAttributeName: placeholderColor])
        textColor = txtColor
    
        let newText = text
        text = newText
    }