如何更改UITextField上的clear按钮的色调颜色?

时间:2022-11-20 14:03:09

I have an auto-generated clear button on my UITextfield, with the default blue tint color. I cannot change the tint color to white. I have tried modifying the storyboard and code without success, and I do not want to use a custom image.

我的UITextfield上有一个自动生成的清除按钮,带有默认的蓝色调。我不能把颜色改成白色。我尝试过修改故事板和代码,但没有成功,我不想使用自定义图像。

How can I change the default clear button tint color without using a custom image?

如何在不使用自定义图像的情况下更改默认的清除按钮颜色?

如何更改UITextField上的clear按钮的色调颜色?

15 个解决方案

#1


65  

Here you go!

在这里你去!

A TintTextField.

TintTextField。

Using no custom image, or added buttons etc.

不使用自定义图像或添加按钮等。

如何更改UITextField上的clear按钮的色调颜色?

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
}

#2


21  

The reason you're having trouble doing this is that the clear button images are not tinted. They are just normal images.

这样做有困难的原因是clear按钮图像没有着色。它们只是普通的图像。

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:

clear按钮是一个按钮,内部的UITextField。就像任何一个按钮一样,它可以有一个图像。特别是,它有两个图像:一个用于正常状态,一个用于突出显示的状态。OP反对的蓝色部分是突出显示的图像,当出现clear按钮时,可以运行此代码来捕获该图像:

    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:

一旦你捕捉到它,你会发现它是一个14x14的双分辨率tiff图像,这里是:

如何更改UITextField上的clear按钮的色调颜色?

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).

理论上,您可以将图像更改为不同的颜色,并可以将其指定为文本视图的clear按钮的图像,以显示突出显示的状态。但在实践中,这一点并不容易做到,因为按钮并不总是存在;当它不存在的时候,你不能提及它(它不仅仅是无形的;它实际上不是视图层次结构的一部分,所以没有办法访问它。

Moreover, there is no UITextField API to customize the clear button.

此外,没有UITextField API来定制clear按钮。

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.

因此,最简单的解决方案是这里建议的:创建一个带有自定义普通和突出显示图像的按钮,并将其作为UITextField的rightView提供。然后,您将clearButtonMode设置为Never(因为您使用的是正确的视图)和rightViewMode设置为您喜欢的任何类型。

如何更改UITextField上的clear按钮的色调颜色?

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.

当然,您必须检测这个按钮上的点击,并通过清除文本字段的文本进行响应;但这很容易做到,并且留给读者作为练习。

#3


15  

Basing on @Mikael Hellman response I've prepared similar implementation of UITextField subclass for Objective-C. The only difference is that I allow to have separate colors for Normal and Highlighted states.

基于@Mikael Hellman响应,我为Objective-C准备了UITextField子类的类似实现。唯一的区别是,我允许对正常状态和突出显示状态使用不同的颜色。

.h file

. h文件

#import <UIKit/UIKit.h>


@interface TextFieldTint : UITextField

-(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted;
-(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal;

@end

.m file

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

#4


8  

In Swift you can write the extension and use on any textfield in your project.

在Swift中,您可以编写扩展名并在项目中的任何textfield上使用。

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

#5


4  

You can use KVO to access the clear button and update it:

您可以使用KVO访问clear按钮并更新它:

    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];

    }

Note: This solution is not future proof - if Apple changes the implementation of of the clear button this will gracefully stop working.

注意:这个解决方案并不是未来的证明——如果苹果改变了clear按钮的实现,它将优雅地停止工作。

#6


3  

Here is Swift 3 updated solution:

以下是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 = ""
    }
}

Enjoy ;)

喜欢。)

#7


3  

For Swift 4, add this to a subclass of UITextField:

对于Swift 4,将其添加到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
        }
    }
}

#8


2  

If you use UIAppearance in your app you can set the tintColor for the clear button at runtime.

如果在应用程序中使用UIAppearance,你可以在运行时为clear按钮设置tintColor。

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

At startup we call a class function in our AppDelegate that has a number of other controls that have their .appearance() configured in it.

在启动时,我们在AppDelegate中调用一个类函数,它有许多其他控件,其中配置了它们的.appearance()。

Suppose your class to set the appearance on your app is called Beautyify you would create something like this:

假设你的类在你的app上设置外观叫做Beautyify你会创建这样的东西:

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

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

Then inside of AppDelegate didFinishLaunchingWithOptions just call it.

然后在AppDelegate的内部didFinishLaunchingWithOptions就叫它。

Beautify.applyAppearance()

Beautify.applyAppearance()

It's a great way to configure the appearance of things in your application all at the same time.

这是同时配置应用程序中事物外观的一种好方法。

#9


2  

It could be even easier than the highest rated answer, available for iOS 7 and later.

它甚至可能比最高评级的答案还要简单,iOS 7以及以后的版本都有。

@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

#10


2  

This worked for me using objective-C. I pulled pieces from other threads on this topic and came up with this solution:

这在objective-C中行得通。我从这个主题的其他线程中提取了一些片段,并提出了这个解决方案:

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

#11


1  

Answer posted by matt above is correct. The clear button inside UITextField doesn't exist if not shown. One can try to access it right after UITextField performs its layoutSubviews and check for existence of the button. The easiest approach is to subclass a UITextField, override layoutSubviews and if the button is shown for the first time, store it's original image(s) for later use, and then during any subsequent show-ups apply a tint.

马特上传的答案是正确的。如果没有显示,则UITextField中的clear按钮不存在。在UITextField执行其layoutSubviews并检查按钮是否存在之后,可以尝试访问它。最简单的方法是对UITextField进行子类化,覆盖layoutSubviews,如果第一次显示按钮,将它的原始图像存储起来以供以后使用,然后在以后的显示中应用tint。

Below I'm showing you how to do this using extension because this way you are able to apply your custom tint to any UITextField, including those nested in ready classes like UISearchBar.

下面我将向您展示如何使用扩展来实现这一点,因为通过这种方式,您可以将自定义色调应用到任何UITextField,包括那些嵌套在现成类(如UISearchBar)中的。

Have fun and give thumbs up if you like it :)

如果你喜欢的话,就去找点乐子吧。

Swift 3.2

斯威夫特3.2

Here is the main extension:

这里是主要的扩展:

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<UIImage> {
                return cl.underlying
            }
            return nil
        }
        set {
            objc_setAssociatedObject(self, &UITextField_AssociatedKeys.originalImage, Wrapper<UIImage>(newValue), .OBJC_ASSOCIATION_RETAIN)
        }
    }

    var clearButtonTint: UIColor? {
        get {
            if let cl = objc_getAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint) as? Wrapper<UIColor> {
                return cl.underlying
            }
            return nil
        }
        set {
            UITextField.runOnce
            objc_setAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint, Wrapper<UIColor>(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()
    }

}

Here are additional snippets used in the code above:

下面是上面代码中使用的附加代码片段:

Nice wrapper for any stuff you would like to access object-wise:

对于任何你想要访问对象方面的东西来说,好的包装:

class Wrapper<T> {
    var underlying: T?

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

A handful extension for finding nested subviews of any type:

查找任何类型的嵌套子视图的几个扩展:

extension UIView {

    static func find<T>(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
    }

}

Extension for UIImage to apply a tint color

UIImage的扩展,用于应用色彩

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
    }

}

...and finally Swizzling stuff:

…最后纵酒东西:

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

}

#12


0  

After going through all the answers and possibilities, I have found this simple and straight forward solution.

在经历了所有的答案和可能性之后,我找到了这个简单而直接的解决方案。

-(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];

#13


0  

In SWIFT 3 : this is working for me

斯威夫特3:这对我很有效

    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
    }

#14


0  

You can use my library LSCategories to do that with one line:

你可以用我的图书馆的笔记来做这一行:

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

It does NOT use any private api, it does NOT search for original UIButton in UITextField subviews hierarchy and it does NOT require to subclass UITextField as some other answers here. Instead it uses rightView property to mimic system clear button therefore you do not need to worry that it will stop working in the future if Apple changes something. It works in Swift also.

它不使用任何私有api,不搜索UITextField子视图层次结构中的原始UIButton,也不需要将UITextField作为其他答案的子类。相反,它使用rightView属性来模拟system clear按钮,因此你不必担心,如果苹果改变了某些东西,它将在未来停止工作。它也适用于Swift。

#15


0  

Swift 4, this works for me (change the tintColor to your own color):

Swift 4,这款适合我(将色调改为您自己的颜色):

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

Need to call it in viewDidLayoutSubviews() so that you make sure it gets called eventually, because there're different clearButtonMode situations (always, whileEditing, etc.). I believe that these buttons are created lazily. So call it in viewDidLoad() mostly don't work.

需要在viewDidLayoutSubviews()中调用它,以便确保最终调用它,因为有不同的clearButtonMode情况(总是,while编辑等等)。我相信这些按钮是随意设计的。所以,在viewDidLoad()中调用它,大多数都不起作用。

#1


65  

Here you go!

在这里你去!

A TintTextField.

TintTextField。

Using no custom image, or added buttons etc.

不使用自定义图像或添加按钮等。

如何更改UITextField上的clear按钮的色调颜色?

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
}

#2


21  

The reason you're having trouble doing this is that the clear button images are not tinted. They are just normal images.

这样做有困难的原因是clear按钮图像没有着色。它们只是普通的图像。

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:

clear按钮是一个按钮,内部的UITextField。就像任何一个按钮一样,它可以有一个图像。特别是,它有两个图像:一个用于正常状态,一个用于突出显示的状态。OP反对的蓝色部分是突出显示的图像,当出现clear按钮时,可以运行此代码来捕获该图像:

    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:

一旦你捕捉到它,你会发现它是一个14x14的双分辨率tiff图像,这里是:

如何更改UITextField上的clear按钮的色调颜色?

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).

理论上,您可以将图像更改为不同的颜色,并可以将其指定为文本视图的clear按钮的图像,以显示突出显示的状态。但在实践中,这一点并不容易做到,因为按钮并不总是存在;当它不存在的时候,你不能提及它(它不仅仅是无形的;它实际上不是视图层次结构的一部分,所以没有办法访问它。

Moreover, there is no UITextField API to customize the clear button.

此外,没有UITextField API来定制clear按钮。

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.

因此,最简单的解决方案是这里建议的:创建一个带有自定义普通和突出显示图像的按钮,并将其作为UITextField的rightView提供。然后,您将clearButtonMode设置为Never(因为您使用的是正确的视图)和rightViewMode设置为您喜欢的任何类型。

如何更改UITextField上的clear按钮的色调颜色?

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.

当然,您必须检测这个按钮上的点击,并通过清除文本字段的文本进行响应;但这很容易做到,并且留给读者作为练习。

#3


15  

Basing on @Mikael Hellman response I've prepared similar implementation of UITextField subclass for Objective-C. The only difference is that I allow to have separate colors for Normal and Highlighted states.

基于@Mikael Hellman响应,我为Objective-C准备了UITextField子类的类似实现。唯一的区别是,我允许对正常状态和突出显示状态使用不同的颜色。

.h file

. h文件

#import <UIKit/UIKit.h>


@interface TextFieldTint : UITextField

-(void) setColorButtonClearHighlighted:(UIColor *)colorButtonClearHighlighted;
-(void) setColorButtonClearNormal:(UIColor *)colorButtonClearNormal;

@end

.m file

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

#4


8  

In Swift you can write the extension and use on any textfield in your project.

在Swift中,您可以编写扩展名并在项目中的任何textfield上使用。

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

#5


4  

You can use KVO to access the clear button and update it:

您可以使用KVO访问clear按钮并更新它:

    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];

    }

Note: This solution is not future proof - if Apple changes the implementation of of the clear button this will gracefully stop working.

注意:这个解决方案并不是未来的证明——如果苹果改变了clear按钮的实现,它将优雅地停止工作。

#6


3  

Here is Swift 3 updated solution:

以下是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 = ""
    }
}

Enjoy ;)

喜欢。)

#7


3  

For Swift 4, add this to a subclass of UITextField:

对于Swift 4,将其添加到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
        }
    }
}

#8


2  

If you use UIAppearance in your app you can set the tintColor for the clear button at runtime.

如果在应用程序中使用UIAppearance,你可以在运行时为clear按钮设置tintColor。

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

At startup we call a class function in our AppDelegate that has a number of other controls that have their .appearance() configured in it.

在启动时,我们在AppDelegate中调用一个类函数,它有许多其他控件,其中配置了它们的.appearance()。

Suppose your class to set the appearance on your app is called Beautyify you would create something like this:

假设你的类在你的app上设置外观叫做Beautyify你会创建这样的东西:

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

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

Then inside of AppDelegate didFinishLaunchingWithOptions just call it.

然后在AppDelegate的内部didFinishLaunchingWithOptions就叫它。

Beautify.applyAppearance()

Beautify.applyAppearance()

It's a great way to configure the appearance of things in your application all at the same time.

这是同时配置应用程序中事物外观的一种好方法。

#9


2  

It could be even easier than the highest rated answer, available for iOS 7 and later.

它甚至可能比最高评级的答案还要简单,iOS 7以及以后的版本都有。

@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

#10


2  

This worked for me using objective-C. I pulled pieces from other threads on this topic and came up with this solution:

这在objective-C中行得通。我从这个主题的其他线程中提取了一些片段,并提出了这个解决方案:

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

#11


1  

Answer posted by matt above is correct. The clear button inside UITextField doesn't exist if not shown. One can try to access it right after UITextField performs its layoutSubviews and check for existence of the button. The easiest approach is to subclass a UITextField, override layoutSubviews and if the button is shown for the first time, store it's original image(s) for later use, and then during any subsequent show-ups apply a tint.

马特上传的答案是正确的。如果没有显示,则UITextField中的clear按钮不存在。在UITextField执行其layoutSubviews并检查按钮是否存在之后,可以尝试访问它。最简单的方法是对UITextField进行子类化,覆盖layoutSubviews,如果第一次显示按钮,将它的原始图像存储起来以供以后使用,然后在以后的显示中应用tint。

Below I'm showing you how to do this using extension because this way you are able to apply your custom tint to any UITextField, including those nested in ready classes like UISearchBar.

下面我将向您展示如何使用扩展来实现这一点,因为通过这种方式,您可以将自定义色调应用到任何UITextField,包括那些嵌套在现成类(如UISearchBar)中的。

Have fun and give thumbs up if you like it :)

如果你喜欢的话,就去找点乐子吧。

Swift 3.2

斯威夫特3.2

Here is the main extension:

这里是主要的扩展:

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<UIImage> {
                return cl.underlying
            }
            return nil
        }
        set {
            objc_setAssociatedObject(self, &UITextField_AssociatedKeys.originalImage, Wrapper<UIImage>(newValue), .OBJC_ASSOCIATION_RETAIN)
        }
    }

    var clearButtonTint: UIColor? {
        get {
            if let cl = objc_getAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint) as? Wrapper<UIColor> {
                return cl.underlying
            }
            return nil
        }
        set {
            UITextField.runOnce
            objc_setAssociatedObject(self, &UITextField_AssociatedKeys.clearButtonTint, Wrapper<UIColor>(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()
    }

}

Here are additional snippets used in the code above:

下面是上面代码中使用的附加代码片段:

Nice wrapper for any stuff you would like to access object-wise:

对于任何你想要访问对象方面的东西来说,好的包装:

class Wrapper<T> {
    var underlying: T?

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

A handful extension for finding nested subviews of any type:

查找任何类型的嵌套子视图的几个扩展:

extension UIView {

    static func find<T>(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
    }

}

Extension for UIImage to apply a tint color

UIImage的扩展,用于应用色彩

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
    }

}

...and finally Swizzling stuff:

…最后纵酒东西:

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

}

#12


0  

After going through all the answers and possibilities, I have found this simple and straight forward solution.

在经历了所有的答案和可能性之后,我找到了这个简单而直接的解决方案。

-(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];

#13


0  

In SWIFT 3 : this is working for me

斯威夫特3:这对我很有效

    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
    }

#14


0  

You can use my library LSCategories to do that with one line:

你可以用我的图书馆的笔记来做这一行:

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

It does NOT use any private api, it does NOT search for original UIButton in UITextField subviews hierarchy and it does NOT require to subclass UITextField as some other answers here. Instead it uses rightView property to mimic system clear button therefore you do not need to worry that it will stop working in the future if Apple changes something. It works in Swift also.

它不使用任何私有api,不搜索UITextField子视图层次结构中的原始UIButton,也不需要将UITextField作为其他答案的子类。相反,它使用rightView属性来模拟system clear按钮,因此你不必担心,如果苹果改变了某些东西,它将在未来停止工作。它也适用于Swift。

#15


0  

Swift 4, this works for me (change the tintColor to your own color):

Swift 4,这款适合我(将色调改为您自己的颜色):

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

Need to call it in viewDidLayoutSubviews() so that you make sure it gets called eventually, because there're different clearButtonMode situations (always, whileEditing, etc.). I believe that these buttons are created lazily. So call it in viewDidLoad() mostly don't work.

需要在viewDidLayoutSubviews()中调用它,以便确保最终调用它,因为有不同的clearButtonMode情况(总是,while编辑等等)。我相信这些按钮是随意设计的。所以,在viewDidLoad()中调用它,大多数都不起作用。