How to change the tint color of the clear button on a UITextField
The reason you're having trouble doing this is that the clear button images are not tinted. They are just normal images.
The clear button is a button, internal to the UITextField. Like any button, it can have an image, and it does. In particular, it has two images: one for the Normal state, and one for the Highlighted state. The blue one to which the OP is objecting is the Highlighted image, and it can be captured by running this code at the time when the clear button is present:
let tf = self.tf // the text view
for sv in tf.subviews as! [UIView] {
if sv is UIButton {
let b = sv as! UIButton
if let im = b.imageForState(.Highlighted) {
// im is the blue x
}
}
}
Once you capture it, you will find that it is a 14x14 double-resolution tiff image, and here it is:
In theory, you can change the image to a different color, and you can assign it as the text view's clear button's image for the highlighted state. But in practice this is not at all easy to do, because the button is not always present; you cannot refer to it when it is absent (it isn't just invisible; it is actually not part of the view hierarchy at all, so there's no way to access it).
Moreover, there is no UITextField API to customize the clear button.
Thus, the simplest solution is what is advised here: create a button with custom Normal and Highlighted images and supply it as the UITextField's rightView
. You then set the clearButtonMode
to Never (since you are using the right view instead) and the rightViewMode
to whatever you like.
You will, of course, then have to detect a tap on this button and respond by clearing the text field's text; but this is easy to do, and is left as an exercise for the reader.
Here you go!
A TintTextField.
Using no custom image, or added buttons etc.
class TintTextField: UITextField {
var tintedClearImage: UIImage?
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupTintColor()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setupTintColor()
}
func setupTintColor() {
self.borderStyle = UITextField.BorderStyle.roundedRect
self.layer.cornerRadius = 8.0
self.layer.masksToBounds = true
self.layer.borderColor = self.tintColor.cgColor
self.layer.borderWidth = 1.5
self.backgroundColor = .clear
self.textColor = self.tintColor
}
override func layoutSubviews() {
super.layoutSubviews()
self.tintClearImage()
}
private func tintClearImage() {
for view in subviews {
if view is UIButton {
let button = view as! UIButton
if let image = button.image(for: .highlighted) {
if self.tintedClearImage == nil {
tintedClearImage = self.tintImage(image: image, color: self.tintColor)
}
button.setImage(self.tintedClearImage, for: .normal)
button.setImage(self.tintedClearImage, for: .highlighted)
}
}
}
}
private func tintImage(image: UIImage, color: UIColor) -> UIImage {
let size = image.size
UIGraphicsBeginImageContextWithOptions(size, false, image.scale)
let context = UIGraphicsGetCurrentContext()
image.draw(at: .zero, blendMode: CGBlendMode.normal, alpha: 1.0)
context?.setFillColor(color.cgColor)
context?.setBlendMode(CGBlendMode.sourceIn)
context?.setAlpha(1.0)
let rect = CGRect(x: CGPoint.zero.x, y: CGPoint.zero.y, width: image.size.width, height: image.size.height)
UIGraphicsGetCurrentContext()?.fill(rect)
let tintedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return tintedImage ?? UIImage()
}
}