Cómo cambiar el color del tinte del botón borrar en un UITextField

Tengo un botón claro generado automáticamente en mi UITextfield, con el color de tinte azul predeterminado. No puedo cambiar el color del tinte a blanco. Intenté modificar el guión gráfico y el código sin éxito, y no quiero usar una imagen personalizada.

¿Cómo puedo cambiar el color predeterminado del tinte del botón claro sin usar una imagen personalizada?

clickeado

¡Aqui tienes!

A TintTextField.

No usar imágenes personalizadas, ni botones añadidos, etc.

enter image description here

class TintTextField: UITextField { var tintedClearImage: UIImage? required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupTintColor() } override init(frame: CGRect) { super.init(frame: frame) setupTintColor() } func setupTintColor() { clearButtonMode = UITextFieldViewMode.WhileEditing borderStyle = UITextBorderStyle.RoundedRect layer.cornerRadius = 8.0 layer.masksToBounds = true layer.borderColor = tintColor.CGColor layer.borderWidth = 1.5 backgroundColor = UIColor.clearColor() textColor = tintColor } override func layoutSubviews() { super.layoutSubviews() tintClearImage() } private func tintClearImage() { for view in subviews as! [UIView] { if view is UIButton { let button = view as! UIButton if let uiImage = button.imageForState(.Highlighted) { if tintedClearImage == nil { tintedClearImage = tintImage(uiImage, tintColor) } button.setImage(tintedClearImage, forState: .Normal) button.setImage(tintedClearImage, forState: .Highlighted) } } } } } func tintImage(image: UIImage, color: UIColor) -> UIImage { let size = image.size UIGraphicsBeginImageContextWithOptions(size, false, image.scale) let context = UIGraphicsGetCurrentContext() image.drawAtPoint(CGPointZero, blendMode: CGBlendMode.Normal, alpha: 1.0) CGContextSetFillColorWithColor(context, color.CGColor) CGContextSetBlendMode(context, CGBlendMode.SourceIn) CGContextSetAlpha(context, 1.0) let rect = CGRectMake( CGPointZero.x, CGPointZero.y, image.size.width, image.size.height) CGContextFillRect(UIGraphicsGetCurrentContext(), rect) let tintedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return tintedImage } 

La razón por la que tiene problemas para hacer esto es porque las imágenes de los botones claros no están teñidas. Son solo imágenes normales.

El botón borrar es un botón, interno al UITextField. Como cualquier botón, puede tener una imagen, y lo hace. En particular, tiene dos imágenes: una para el estado Normal y otra para el estado Destacado. El azul al que se opone el OP es la imagen resaltada, y se puede capturar ejecutando este código en el momento en que está presente el botón borrar:

  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 } } } 

Una vez que lo capture, verá que se trata de una imagen tiff de doble resolución de 14×14, y aquí está:

enter image description here

En teoría, puede cambiar la imagen a un color diferente, y puede asignarla como la imagen del botón claro de la vista de texto para el estado resaltado. Pero en la práctica esto no es nada fácil de hacer, porque el botón no siempre está presente; no puede referirse a él cuando está ausente (no es solo invisible, en realidad no es parte de la jerarquía de vista, por lo que no hay forma de acceder a él).

Además, no hay una API UITextField para personalizar el botón de borrar.

Por lo tanto, la solución más simple es la que se recomienda aquí : crear un botón con imágenes personalizadas Normal y Destacadas y suministrarlo como el RightView de rightView . A continuación, establece clearButtonMode en Never (ya que está utilizando la vista derecha en su lugar) y rightViewMode en lo que quiera.

enter image description here

Por supuesto, tendrá que detectar un toque en este botón y responder borrando el texto del campo de texto; pero esto es fácil de hacer, y se deja como un ejercicio para el lector.

Según la respuesta de @Mikael Hellman, he preparado una implementación similar de la subclase UITextField para Objective-C. La única diferencia es que permití tener colores separados para los estados Normal y Destacado.

archivo .h

 #import  @interface TextFieldTint : UITextField -(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted; -(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal; @end 

archivo .m

 #import "TextFieldTint.h" @interface TextFieldTint() @property (nonatomic,strong) UIColor *colorButtonClearHighlighted; @property (nonatomic,strong) UIColor *colorButtonClearNormal; @property (nonatomic,strong) UIImage *imageButtonClearHighlighted; @property (nonatomic,strong) UIImage *imageButtonClearNormal; @end @implementation TextFieldTint -(void) layoutSubviews { [super layoutSubviews]; [self tintButtonClear]; } -(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted { _colorButtonClearHighlighted = colorButtonClearHighlighted; } -(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal { _colorButtonClearNormal = colorButtonClearNormal; } -(UIButton *) buttonClear { for(UIView *v in self.subviews) { if([v isKindOfClass:[UIButton class]]) { UIButton *buttonClear = (UIButton *) v; return buttonClear; } } return nil; } -(void) tintButtonClear { UIButton *buttonClear = [self buttonClear]; if(self.colorButtonClearNormal && self.colorButtonClearHighlighted && buttonClear) { if(!self.imageButtonClearHighlighted) { UIImage *imageHighlighted = [buttonClear imageForState:UIControlStateHighlighted]; self.imageButtonClearHighlighted = [[self class] imageWithImage:imageHighlighted tintColor:self.colorButtonClearHighlighted]; } if(!self.imageButtonClearNormal) { UIImage *imageNormal = [buttonClear imageForState:UIControlStateNormal]; self.imageButtonClearNormal = [[self class] imageWithImage:imageNormal tintColor:self.colorButtonClearNormal]; } if(self.imageButtonClearHighlighted && self.imageButtonClearNormal) { [buttonClear setImage:self.imageButtonClearHighlighted forState:UIControlStateHighlighted]; [buttonClear setImage:self.imageButtonClearNormal forState:UIControlStateNormal]; } } } + (UIImage *) imageWithImage:(UIImage *)image tintColor:(UIColor *)tintColor { UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0); CGContextRef context = UIGraphicsGetCurrentContext(); CGRect rect = (CGRect){ CGPointZero, image.size }; CGContextSetBlendMode(context, kCGBlendModeNormal); [image drawInRect:rect]; CGContextSetBlendMode(context, kCGBlendModeSourceIn); [tintColor setFill]; CGContextFillRect(context, rect); UIImage *imageTinted = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return imageTinted; } @end 

En Swift puedes escribir la extensión y usarla en cualquier campo de texto de tu proyecto.

 extension UITextField { func modifyClearButton(with image : UIImage) { let clearButton = UIButton(type: .custom) clearButton.setImage(image, for: .normal) clearButton.frame = CGRect(x: 0, y: 0, width: 15, height: 15) clearButton.contentMode = .scaleAspectFit clearButton.addTarget(self, action: #selector(UITextField.clear(_:)), for: .touchUpInside) rightView = clearButton rightViewMode = .whileEditing } func clear(_ sender : AnyObject) { self.text = "" sendActions(for: .editingChanged) } } 

Para Swift 4, agréguelo a una subclase de UITextField:

 import UIKit class CustomTextField: UITextField { override func layoutSubviews() { super.layoutSubviews() for view in subviews { if let button = view as? UIButton { button.setImage(button.image(for: .normal)?.withRenderingMode(.alwaysTemplate), for: .normal) button.tintColor = .white } } } } 

Puede usar KVO para acceder al botón de borrar y actualizarlo:

  UIButton *clearButton = [myTextField valueForKey:@"_clearButton"] if([clearButton respondsToSelector:@selector(setImage:forState:)]){ //ensure that the app won't crash in the future if _clearButton reference changes to a different class instance [clearButton setImage:[UIImage imageNamed:@"MyImage.png"] forState:UIControlStateNormal]; } 

Nota: esta solución no es a prueba de futuro: si Apple cambia la implementación del botón borrar esto dejará de funcionar correctamente.

Aquí está la solución actualizada de Swift 3:

 extension UITextField { func modifyClearButtonWithImage(image : UIImage) { let clearButton = UIButton(type: .custom) clearButton.setImage(image, for: .normal) clearButton.frame = CGRect(x: 0, y: 0, width: 15, height: 15) clearButton.contentMode = .scaleAspectFit clearButton.addTarget(self, action: #selector(self.clear(sender:)), for: .touchUpInside) self.rightView = clearButton self.rightViewMode = .whileEditing } func clear(sender : AnyObject) { self.text = "" } } 

Disfrutar;)

Si usa UIAppearance en su aplicación, puede establecer tintColor para el botón de borrar en tiempo de ejecución.

 let textField = UITextField.appearance() textField.tintColor = .greenColor() 

Al inicio llamamos a una función de clase en nuestro AppDelegate que tiene un número de otros controles que tienen su .appearance() configurado en él.

Supongamos que su clase para establecer la apariencia en su aplicación se llama Beautyify usted crearía algo como esto:

 @objc class Beautify: NSObject { class func applyAppearance() { let tableViewAppearance = UITableView.appearance() tableViewAppearance.tintColor = .blueColor() let textField = UITextField.appearance() textField.tintColor = .greenColor() } } 

Luego dentro de AppDelegate didFinishLaunchingWithOptions simplemente llámalo.

Beautify.applyAppearance()

Es una excelente manera de configurar el aspecto de las cosas en tu aplicación, todo al mismo tiempo.

Podría ser incluso más fácil que la respuesta mejor calificada, disponible para iOS 7 y posterior.

 @interface MyTextField @end @implementation MyTextField - (void)layoutSubviews { [super layoutSubviews]; for (UIView *subView in self.subviews) { if ([subView isKindOfClass:[UIButton class]]) { UIButton *button = (UIButton *)subView; [button setImage:[[button imageForState:UIControlStateNormal] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal]; button.tintColor = self.tintColor; } } } @end 

Esto funcionó para mí usando el objective-C. Saqué piezas de otros temas sobre este tema y se me ocurrió esta solución:

 UIButton *btnClear = [self.textFieldUserID valueForKey:@"clearButton"]; [btnClear setImage:[UIImage imageNamed:@"facebookLoginButton"] forState:UIControlStateNormal]; 

La respuesta publicada por matt arriba es correcta. El botón borrar dentro de UITextField no existe si no se muestra. Se puede intentar acceder justo después de que UITextField realiza su layoutSubviews y verifica la existencia del botón. El enfoque más fácil es subclasificar un UITextField , anular layoutSubviews y si el botón se muestra por primera vez, almacenar su (s) imagen (es) original (es) para su uso posterior, y luego, durante los siguientes despliegues aplicar un tinte.

A continuación, le mostraremos cómo hacer esto utilizando la extensión, ya que de esta manera puede aplicar su tinte personalizado a cualquier UITextField, incluidos aquellos nesteds en clases listas como UISearchBar.

Diviértete y renunciar a los pulgares si te gusta 🙂

Swift 3.2

Aquí está la extensión principal:

 import UIKit extension UITextField { private struct UITextField_AssociatedKeys { static var clearButtonTint = "uitextfield_clearButtonTint" static var originalImage = "uitextfield_originalImage" } private var originalImage: UIImage? { get { if let cl = objc_getAssociatedObject(self, &UITextField_AssociatedKeys.originalImage) as? Wrapper { return cl.underlying } return nil } set { objc_setAssociatedObject(self, &UITextField_AssociatedKeys.originalImage, Wrapper(newValue), .OBJC_ASSOCIATION_RETAIN) } } var clearButtonTint: UIColor? { get { if let cl = objc_getAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint) as? Wrapper { return cl.underlying } return nil } set { UITextField.runOnce objc_setAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint, Wrapper(newValue), .OBJC_ASSOCIATION_RETAIN) applyClearButtonTint() } } private static let runOnce: Void = { Swizzle.for(UITextField.self, selector: #selector(UITextField.layoutSubviews), with: #selector(UITextField.uitextfield_layoutSubviews)) }() private func applyClearButtonTint() { if let button = UIView.find(of: UIButton.self, in: self), let color = clearButtonTint { if originalImage == nil { originalImage = button.image(for: .normal) } button.setImage(originalImage?.tinted(with: color), for: .normal) } } func uitextfield_layoutSubviews() { uitextfield_layoutSubviews() applyClearButtonTint() } } 

Aquí hay fragmentos adicionales utilizados en el código anterior:

Buena envoltura para cualquier cosa a la que le gustaría acceder desde el punto de vista del objeto:

 class Wrapper { var underlying: T? init(_ underlying: T?) { self.underlying = underlying } } 

Una pequeña extensión para encontrar subvistas anidadas de cualquier tipo:

 extension UIView { static func find(of type: T.Type, in view: UIView, includeSubviews: Bool = true) -> T? where T: UIView { if view.isKind(of: T.self) { return view as? T } for subview in view.subviews { if subview.isKind(of: T.self) { return subview as? T } else if includeSubviews, let control = find(of: type, in: subview) { return control } } return nil } } 

Extensión para UIImage para aplicar un color de tinte

 extension UIImage { func tinted(with color: UIColor) -> UIImage? { UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) color.set() self.withRenderingMode(.alwaysTemplate).draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: self.size)) let result = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return result } } 

… y finalmente cosas de Swizzling:

 class Swizzle { class func `for`(_ className: AnyClass, selector originalSelector: Selector, with newSelector: Selector) { let method: Method = class_getInstanceMethod(className, originalSelector) let swizzledMethod: Method = class_getInstanceMethod(className, newSelector) if (class_addMethod(className, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) { class_replaceMethod(className, newSelector, method_getImplementation(method), method_getTypeEncoding(method)) } else { method_exchangeImplementations(method, swizzledMethod) } } } 

Swift 4, subclase limpia y concisa

 import UIKit class CustomTextField: UITextField { override func layoutSubviews() { super.layoutSubviews() for view in subviews where view is UIButton { (view as! UIButton).setImage(, for: .normal) } } } 

Después de revisar todas las respuestas y posibilidades, encontré esta solución simple y directa.

 -(void)updateClearButtonColor:(UIColor *)color ofTextField:(UITextField *)textField { UIButton *btnClear = [textField valueForKey:@"_clearButton"]; UIImage * img = [btnClear imageForState:UIControlStateNormal]; if (img) { UIImage * renderingModeImage = [img imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [btnClear setImage:renderingModeImage forState:UIControlStateNormal]; //-- Add states you want to update [btnClear setImage:renderingModeImage forState:UIControlStateSelected]; } [btnClear setTintColor:color]; } [self updateClearButtonColor:[UIColor whiteColor] ofTextField:self.textField]; 

En SWIFT 3: esto está funcionando para mí

  if let clearButton = self.textField.value(forKey: "_clearButton") as? UIButton { // Create a template copy of the original button image let templateImage = clearButton.imageView?.image?.withRenderingMode(.alwaysTemplate) // Set the template image copy as the button image clearButton.setImage(templateImage, for: .normal) clearButton.setImage(templateImage, for: .highlighted) // Finally, set the image color clearButton.tintColor = .white } 

Puedes usar mi biblioteca LSCategories para hacer eso con una línea:

 [textField lsSetClearButtonWithColor:[UIColor redColor] mode:UITextFieldViewModeAlways]; 

NO utiliza ninguna API privada, NO busca el UIButton original en la jerarquía de subvistas de UITextField y NO requiere la subclase de UITextField como algunas otras respuestas aquí. En su lugar, utiliza la propiedad rightView para imitar el botón de borrado del sistema, por lo que no tiene que preocuparse de que deje de funcionar en el futuro si Apple cambia algo. Funciona en Swift también.

Swift 4, esto funciona para mí (cambie el tintColor a su propio color):

 var didSetupWhiteTintColorForClearTextFieldButton = false private func setupTintColorForTextFieldClearButtonIfNeeded() { // Do it once only if didSetupWhiteTintColorForClearTextFieldButton { return } guard let button = yourTextField.value(forKey: "_clearButton") as? UIButton else { return } guard let icon = button.image(for: .normal)?.withRenderingMode(.alwaysTemplate) else { return } button.setImage(icon, for: .normal) button.tintColor = .white didSetupWhiteTintColorForClearTextFieldButton = true } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() setupTintColorForTextFieldClearButtonIfNeeded() } 

Necesita llamarlo en viewDidLayoutSubviews() para asegurarse de que se llame eventualmente, porque hay diferentes situaciones de clearButtonMode ( always , whileEditing , etc.). Creo que estos botones se crean de forma perezosa. Así que llámalo en viewDidLoad() su mayoría no funcionan.