55
votes

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.

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

clicked

24
Looks like global tint isn't honored for the UITextField clear button (for whatever reason!), you can check out this answer and this answer to see how others are doing it. Seems you have to create your own button.radiovisual

24 Answers

77
votes

Here you go!

A TintTextField.

Using no custom image, or added buttons etc.

Image of UITextField with white tint color for cancel button

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

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:

enter image description here

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.

enter image description here

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.

17
votes

For Swift 4, add this to a subclass of 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
            }
        }
    }
}
15
votes

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.

.h file

#import <UIKit/UIKit.h>


@interface TextFieldTint : UITextField

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

@end

.m file

#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
15
votes

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

extension UITextField {
    @objc 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
    }

    @objc func clear(_ sender : AnyObject) {
    if delegate?.textFieldShouldClear?(self) == true {
        self.text = ""
        sendActions(for: .editingChanged)
    }
}
}
5
votes

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

    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.

5
votes

You can use your custom icon and it works in iOS 11,

searchBar.setImage(UIImage(named: "ic_clear"), for: .clear, state: .normal)
4
votes

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

@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
4
votes

Here is Swift 3 updated solution:

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

4
votes

The idea is get the clear button by key clearButton, then re-render the clear image with alwaysTemplate mode.

[Swift 4.2] Just made an extension for UITextField here:

extension UITextField {
    var clearButton: UIButton? {
        return value(forKey: "clearButton") as? UIButton
    }

    var clearButtonTintColor: UIColor? {
        get {
            return clearButton?.tintColor
        }
        set {
            let image =  clearButton?.imageView?.image?.withRenderingMode(.alwaysTemplate)
            clearButton?.setImage(image, for: .normal)
            clearButton?.tintColor = newValue
        }
    }
}

But the problem with this solution is the clear button's image is nil at the time you're calling to set tint color.

So for every one is using RxSwift to observe the image in clear button.

import RxSwift

extension UITextField {
    var clearButton: UIButton? {
        return value(forKey: "clearButton") as? UIButton
    }

    var clearButtonTintColor: UIColor? {
        get {
            return clearButton?.tintColor
        }
        set {
            _ = rx.observe(UIImage.self, "clearButton.imageView.image")
                .takeUntil(rx.deallocating)
                .subscribe(onNext: { [weak self] _ in
                    let image = self?.clearButton?.imageView?.image?.withRenderingMode(.alwaysTemplate)
                    self?.clearButton?.setImage(image, for: .normal)
                })
            clearButton?.tintColor = newValue
        }
    }
}
4
votes

like @Brody Robertson answer, here is the Swift 5 version, it works for me:

let textField = UITextField()
if let button = textField.value(forKey: "clearButton") as? UIButton {
  button.tintColor = .white
  button.setImage(UIImage(named: "yourImage")?.withRenderingMode(.alwaysTemplate), for: .normal)
}

Note: You need to use your icon replace yourImage, or if your target is iOS 13.0 or above, you could replace the method UIImage(named:) with UIImage(systemName: "xmark.circle.fill"). This clear icon is ready for you by Apple in iOS 13.0 or above. I hope this will help! Good luck!

3
votes

I tried a lot of answers until found this solution based in @Mikael Hellman solution. This solution is using Swift 4.2.

The idea is the same:

Using no custom image, or added buttons etc.

And using a custom class that extends UITextField.

class TintClearTextField: UITextField {

    private var updatedClearImage = false

    override func layoutSubviews() {
        super.layoutSubviews()
        tintClearImage()
    }

    private func tintClearImage() {
        if updatedClearImage { return }

        if let button = self.value(forKey: "clearButton") as? UIButton,
            let image = button.image(for: .highlighted)?.withRenderingMode(.alwaysTemplate) {
            button.setImage(image, for: .normal)
            button.setImage(image, for: .highlighted)
            button.tintColor = .white

            updatedClearImage = true
        }
    }
}

You don't need the updatedClearImage, but have in mind that you'll be performing all the logics in every character addition.

I don't even need to set the tintColor to get the result I was looking for. Try commenting that line before setting to your color.

If it doesn't looks like you want, change the .white with your desired color, and that's all.

PS.: I have a field that is already populated in my initial screen, and for this only one the color change with tintColor happens milliseconds after showing the default item color, like a "glitch". I couldn't make it better, but since I'm not using the tintColor, that is ok for me.

Hope it helps :)

2
votes

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

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

In SWIFT 3 : this is working for me

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

Swift 4, this works for me (change the tintColor to your own 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()
}

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.

2
votes

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

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

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

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

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

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

Then inside of AppDelegate didFinishLaunchingWithOptions just call it.

Beautify.applyAppearance()

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

1
votes

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

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.

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.

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

Swift 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

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

}
1
votes

Swift 4, clean and concise Subclass

import UIKit

class CustomTextField: UITextField {
    override func layoutSubviews() {
        super.layoutSubviews()
        for view in subviews where view is UIButton {
            (view as! UIButton).setImage(<MY_UIIMAGE>, for: .normal)
        }
    }
}
1
votes

Create this method.

func configureClearButtonColor() {

    guard let clearButton = textField.value(forKey: "_clearButton") as? UIButton else {
        return
    }
    let templateImage = clearButton.imageView?.image?.withRenderingMode(.alwaysTemplate)
    clearButton.setImage(templateImage, for: .normal)
    clearButton.setImage(templateImage, for: .highlighted)
    clearButton.tintColor = .white
}

And implement your UITextFieldDelegate, at the of textFieldDidEndEditing call the method. That change your image before create some text.

func textFieldDidEndEditing(_ textField: UITextField) {
    configureClearButtonColor()
}
1
votes

Swift 5 solution:

   if let clearButton = yourTextField.value(forKey: "_clearButton") as? UIButton {
       let templateImage = clearButton.imageView?.image?.withRenderingMode(.alwaysTemplate)
       clearButton.setImage(templateImage, for: .normal)
       clearButton.tintColor = .darkGray
   }
0
votes

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.

0
votes

Details

  • Xcode Version 10.1 (10B61)
  • Swift 4.2

Solution

import UIKit

extension UISearchBar {

    func getTextField() -> UITextField? { return value(forKey: "searchField") as? UITextField }

    func setClearButton(color: UIColor) {
        getTextField()?.setClearButton(color: color)
    }
}

extension UITextField {

    private class ClearButtonImage {
        static private var _image: UIImage?
        static private var semaphore = DispatchSemaphore(value: 1)
        static func getImage(closure: @escaping (UIImage?)->()) {
            DispatchQueue.global(qos: .userInteractive).async {
                semaphore.wait()
                DispatchQueue.main.async {
                    if let image = _image { closure(image); semaphore.signal(); return }
                    guard let window = UIApplication.shared.windows.first else { semaphore.signal(); return }
                    let searchBar = UISearchBar(frame: CGRect(x: 0, y: -200, width: UIScreen.main.bounds.width, height: 44))
                    window.rootViewController?.view.addSubview(searchBar)
                    searchBar.text = "txt"
                    searchBar.layoutIfNeeded()
                    _image = searchBar.getTextField()?.getClearButton()?.image(for: .normal)
                    closure(_image)
                    searchBar.removeFromSuperview()
                    semaphore.signal()
                }
            }
        }
    }

    func setClearButton(color: UIColor) {
        ClearButtonImage.getImage { [weak self] image in
            guard   let image = image,
                    let button = self?.getClearButton() else { return }
            button.imageView?.tintColor = color
            button.setImage(image.withRenderingMode(.alwaysTemplate), for: .normal)
        }
    }

    func getClearButton() -> UIButton? { return value(forKey: "clearButton") as? UIButton }
}

Full sample

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let textField = UITextField(frame: CGRect(x: 20, y: 20, width: 200, height: 44))
        view.addSubview(textField)
        textField.backgroundColor = .lightGray
        textField.clearButtonMode = .always
        textField.setClearButton(color: .red)

        let searchBar = UISearchBar(frame: CGRect(x: 20, y: 80, width: 200, height: 44))
        view.addSubview(searchBar)
        searchBar.backgroundColor = .lightGray
        searchBar.setClearButton(color: .red)
    }
}

Result

enter image description here

0
votes

Modification to @3vangelos solution, bypassing this for loop

for view in subviews where view is UIButton {
        (view as! UIButton).setImage(<MY_UIIMAGE>, for: .normal)
    }

My Modification:-

class CustomTextField:UITextField { 
override func layoutSubviews()
    {super.layoutSubviews()
    let clearButton = self.value(forKey: "clearButton") as? UIButton
    clearButton?.setImage(#imageLiteral(resourceName: "icons8-cancel.pdf"), for: .normal)
    clearButton?.tintColor = UIColor(<YOUR_COLOR>)
}

Same solution can be used in UISearchBar with some add on code:-

 override func viewWillAppear(_ animated: Bool)
{
    super.viewWillAppear(animated)
if let textField = agentsSearchBar.value(forKey: "searchField") as? UITextField
    {
let clearButton = textField.value(forKey: "clearButton") as? UIButton
clearButton?.setImage(#imageLiteral(resourceName: "icons8-cancel.pdf"), for: .normal)
clearButton?.tintColor = UIColor(<YOUR_COLOR>)
} }

image (icons8-cancel.pdf) can be downloaded at https://icons8.com/icon/set/clear-button/ios7# and added to your image assets with the following attributes enter image description here