100

How can I change the text color of a UISearchBar?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
MrTourkos
  • 1,922
  • 2
  • 18
  • 22

25 Answers25

118

You have to access the UITextField inside the UISearchBar. You can do that by using valueForKey("searchField")

var textFieldInsideSearchBar = yourSearchbar.valueForKey("searchField") as? UITextField

textFieldInsideSearchBar?.textColor = yourcolor

Swift 3 update

let textFieldInsideSearchBar = yourSearchbar.value(forKey: "searchField") as? UITextField

textFieldInsideSearchBar?.textColor = yourcolor
esilver
  • 27,713
  • 23
  • 122
  • 168
Christian
  • 22,585
  • 9
  • 80
  • 106
  • Thanks! But is that API public or private? – MrTourkos Feb 15 '15 at 17:43
  • It doesn't compile. After a few changes it did, but then threw a runtime error complaining "Array index out of range" and if i change it to subView[0] it's a UIView that cannot be casted to a textField. Notice that i'm using Swift 1.2 if that has something to do. Thanks and sorry for the late reply. – MrTourkos Feb 20 '15 at 12:16
  • 1
    I've edited my answer. You can access the field by using valueforkey("searchField") – Christian Feb 20 '15 at 12:20
  • Alright now working great! Just a minor, you need to unwrap textFieldInsideSearchBar?.textColor = yourcolor to access textColor Thanks man! – MrTourkos Feb 20 '15 at 12:24
  • How did you find the name of the searchField value ? I'd like to change the font of the cancel button but I don't find the value for it. – YoanGJ Jun 01 '16 at 08:37
  • not working at all ---- Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ valueForUndefinedKey:]: this class is not key value coding-compliant for the key searchField.' – bLacK hoLE Jun 04 '16 at 09:06
  • 7
    It's not private API but it's very fragile and can break on any iOS update. You shouldn't ever use things like these in production code – Lope Jul 10 '17 at 10:19
  • @NextDeveloper Have you checked how long ago this answer was posted? It’s possible that it doesn’t work anymore. Feel free to show another approach. – Christian Aug 25 '17 at 09:40
  • 3
    @Christian - it doesn't matter when the original answer was posted, it still relies on private API. If it was public, you wouldn't need to access `searchField` via KVC. – Greg Brown Nov 29 '17 at 12:05
  • 2
    Downvote. See @juanjo's answer and my comment for a much more robust approach approved by Apple and far less likely to break. – RobP Jun 27 '18 at 02:19
  • 2
    Don't use this answer, you are accessing private APIs and it could get your app rejected. – aryaxt Sep 23 '18 at 17:50
76

If you want to set text color for UISearchBar in storyboard (without code), it is easy to do as well (in identity inspector). Here is a red text for search bar.

enter image description here

interrupt
  • 2,030
  • 17
  • 14
60

If you only need to make it readable on a dark background you can change the barStyle. The following makes text and buttons in the searchbar white:

searchController.searchBar.barStyle = .black
Bacon
  • 792
  • 5
  • 8
57

Working in Swift 4 for me:

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.white]

Swift 4.2, IOS 12:

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
Chandana
  • 23
  • 6
chronikum
  • 716
  • 5
  • 12
32
public extension UISearchBar {

    public func setTextColor(color: UIColor) {
        let svs = subviews.flatMap { $0.subviews }
        guard let tf = (svs.filter { $0 is UITextField }).first as? UITextField else { return }
        tf.textColor = color
    }
}
Adam Waite
  • 19,175
  • 22
  • 126
  • 148
14

This works for me on iOS 11, Xcode 9:

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).textColor = UIColor.blue

I write it in the AppDelegate but I guess it works if you put it somewhere else too.

juanjo
  • 3,737
  • 3
  • 39
  • 44
  • 3
    This is a much more robust approach than the key-value nonsense in the accepted answer and other answers. However, Apple in their wisdom has deprecated the API you use here and offers a new version for iOS 9.0 and above, like so: `[[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTextColor:[UIColor blueColor]];` This is of course Objective-C, with obvious translation to Swift using `appearance(whenContainedInInstancesOf:)` – RobP Jun 27 '18 at 02:16
  • 2
    Doesn't seem to work for me in Xcode 10, iOS 12, on an actual device. – Oded Nov 16 '18 at 02:17
  • @RobP this is the same hack based on assumption that there is a `UITextField` inside the `UISearchBar`. But instead of localizing ugliness in a place of usage it's spilling it all over the project. – Zapko May 18 '21 at 16:42
11

The most convenient way I think is to set a textColor property in UISearchBar.

Swift 3.0

    extension UISearchBar {

       var textColor:UIColor? {
           get {
               if let textField = self.value(forKey: "searchField") as? 
   UITextField  {
                   return textField.textColor
               } else {
                   return nil
               }
           }

           set (newValue) {
               if let textField = self.value(forKey: "searchField") as? 
   UITextField  {
                   textField.textColor = newValue
               }
           }
       }
   }

Usage

searchBar.textColor = UIColor.blue // Your color

Swift 2.3

extension UISearchBar {

 var textColor:UIColor? {
     get {
         if let textField = self.valueForKey("searchField") as? UITextField  {
             return textField.textColor
         } else {
             return nil
         }
     }

     set (newValue) {
         if let textField = self.valueForKey("searchField") as? UITextField  {
             textField.textColor = newValue
         }
     }
 }
} 

You would use it as:

searchBar.textColor = UIColor.blueColor() // Your color
Tal Zion
  • 6,308
  • 3
  • 50
  • 73
11

Since Xcode 11 and iOS 13 it has become possible to access the text field directly:

searchBar.searchTextField

You could write some code to always make it accessible like this.

extension UISearchBar {
    public var textField: UITextField? {
        if #available(iOS 13.0, *) {
            return searchTextField
        } 

        guard let firstSubview = subviews.first else {
            assertionFailure("Could not find text field")
            return nil
        }

        for view in firstSubview.subviews {
            if let textView = view as? UITextField {
                return textView
            }
        }

        assertionFailure("Could not find text field")

        return nil
    }
}

You could also make it not optional with fatal errors, this code is tested since iOS 7 up to iOS 13GM. But i would just go for the optional version.

extension UISearchBar {
    public var textField: UITextField {
        if #available(iOS 13.0, *) {
            return searchTextField
        }

        guard let firstSubview = subviews.first else {
            fatalError("Could not find text field")
        }

        for view in firstSubview.subviews {
            if let textView = view as? UITextField {
                return textView
            }
        }

       fatalError("Could not find text field")
    }
}
Saren Inden
  • 3,450
  • 4
  • 32
  • 45
6

Try this,

searchBar.searchTextField.textColor = .white

I am using this with app targeted iOS 11 onwards.

[Update] I observed, the app crashes on older versions (< iOS 13), But compiler never complained about the version check, someone please explain why this happened.

infiniteLoop
  • 2,135
  • 1
  • 25
  • 29
4

I tried a few of the solutions written above but they didn't work (anymore, I guess).

If you only want to handle iOS 13:

mySearchBar.searchTextField.textColor = .red

But if you want to handle older iOS too, Here is the way I did :

Create a custom UISearchBar class, called SearchBar : UISearchBar, UISearchBarDelegate This SearchBar will have the UISearchBarDelegate methods I wanna handle and its delegate set.

And I add to the class:

    var textField: UITextField? {
        if #available(iOS 13.0, *) {
            return self.searchTextField
        }
        return subviews.first?.subviews.first(where: { $0 as? UITextField != nil }) as? UITextField
    }

Short explanation:

With iOS13 now, you can access the UITextField thanks to UISearchBar.searchTextField, which is of type UISearchTextField, which inherits from UITextField.

Since I know my hierarchy, I know my textField won't be nill for older versions so in both case, I get a textfield I can easily customize, working on every version, from 9 to 13 today.

Here is the full code needed to make it work:


class SearchBar: UISearchBar, UISearchBarDelegate {

    var textField: UITextField? {
        if #available(iOS 13.0, *) {
            return self.searchTextField
        }
        return subviews.first?.subviews.first(where: { $0 as? UITextField != nil }) as? UITextField
    }


    override func awakeFromNib() {
        super.awakeFromNib()

        delegate = self

        if let textField = textField {
            textField.textColor = .red
            textField.clearButtonMode = .whileEditing
            textField.returnKeyType = .search
        }
    }

}

You can also set some customization on SearchBar by adding this on the :

        let searchBar = UISearchBar.appearance(whenContainedInInstancesOf: [SearchBar.self])
        searchBar.backgroundImage = UIImage()
        searchBar.isTranslucent = false
        searchBar.returnKeyType = .search

Then you set it to the XIB / Storyboard and you handle it like if it were a simple UISearchBar (if you did not forget the delegates !).

Bryan ORTIZ
  • 306
  • 3
  • 17
3

You can do this by accessing the UITextField inside the searchBar, then you can change its background color, text color, and all other UITextField properties

add the following extension to access the textField

extension UISearchBar {
    /// Return text field inside a search bar
    var textField: UITextField? {
        let subViews = subviews.flatMap { $0.subviews }
        guard let textField = (subViews.filter { $0 is UITextField }).first as? UITextField else { return nil
        }
        return textField
    }
}
Omar Albeik
  • 1,332
  • 13
  • 17
3

Swift 5.2 & iOS 13.3.1:-

It works fine.

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]

3

This worked for me.

    if #available(iOS 13.0, *) {
     searchBar.searchTextField.textColor = .white
    }
2

(This solution only tested for Xcode 10 & iOS 12.) Add an extension to access the search bar's text field:

extension UISearchBar {
    var textField: UITextField? {
        return subviews.first?.subviews.compactMap { $0 as? UITextField }.first
    }
}

Then use that property to set the text color of the text field in your search bar:

let searchBar = UISearchBar()
searchBar.textField?.textColor = UIColor.white // or whichever color you want

// EDIT

The code above does not work for iOS 13. A better way to handle this is to use:

extension UISearchBar {
    var textField: UITextField? {
        return self.subviews(ofType: UITextField.self).first
    }
}

extension UIView {
    var recursiveSubviews: [UIView] {
        return self.subviews + self.subviews.flatMap { $0.recursiveSubviews }
    }

    func subviews<T: UIView>(ofType: T.Type) -> [T] {
        return self.recursiveSubviews.compactMap { $0 as? T }
    }
}
  • for iOS 13 **return subviews.first?.subviews.last?.subviews.compactMap { $0 as? UITextField }.last** – Taras Nov 05 '19 at 04:04
2

In Swift 5 you can do something like below:

yourSearchBar.searchTextField.textColor = .yourColor
Syed Ali Salman
  • 2,894
  • 4
  • 33
  • 48
johnDoe
  • 709
  • 11
  • 29
1

Here is a Xamarin.iOS C# version of the "find the UITextField" approach. It will not crash if the UITextField disappears in future iOS view hierarchy.

var tf = searchBar.AllSubViews().FirstOrDefault(v => v is UITextField);
if (tf != null) 
    (tf as UITextField).TextColor = UIColor.White;

public static IEnumerable<UIView> AllSubViews(this UIView view)
{
    foreach (var v in view.Subviews)
    {
        yield return v;
        foreach (var sv in v.AllSubViews())
        {
            yield return sv;
        }
    }
}
t9mike
  • 1,546
  • 2
  • 19
  • 31
1

//Try this guy

yourSearchbar.searchTextField.textColor = .white
Nrv
  • 280
  • 1
  • 6
0

In my situation solution is

id appearance = [UITextField appearanceWhenContainedInInstancesOfClasses:@[UISearchBar.class, BCRSidebarController.class]];
[appearance setTextColor:[UIColor.whiteColor colorWithAlphaComponent:0.56]];
poGUIst
  • 299
  • 4
  • 10
0

Obj-C

UITextField *textField = [self.yourSearchbar valueForKey:@"_searchField"];
textField.textColor = [UIColor redColor];

Swift 4.x

let textField = yourSearchbar.value(forKey: "searchField") as? UITextField
textField?.textColor = UIColor.red
Argus
  • 2,241
  • 1
  • 22
  • 27
0

Swift 5:

searchBar[keyPath: \.searchTextField].textColor = UIColor(...)

ramzesenok
  • 5,469
  • 4
  • 30
  • 41
0

you can set the color for self.searchBar.searchTextField.textColor below code in viewDidLoad works.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.searchBar.searchTextField.textColor = [UIColor whiteColor];
}
pratima s
  • 1
  • 1
0

SwiftUI, Swift 5

In SwiftUI, the

init(){

   UITextfiled.appearance().textColor = .white
}

doesn't work. But you can just use the

.foregroundColor(.white)

modifier to change the searchable()'s text color.

If you also want to change the tintColor of the searchbar inside a NavigationView{}. You could init the inti() function of the view.

init(){

   UINavigationBar.appearance().tintColor = .white

}
var body:some View{  
   
    NavigationView{
   
   }
}
William Tong
  • 479
  • 7
  • 14
0

In my case I had the searchBar of a UISearchController in the navigationBar. For some reason textColor only works when called after adding the searchController as an item in the navigation.

previous code...
navigationItem.searchController = searchController
// Only after the assignment it works
searchController.searchBar.searchTextField.textColor = your color
0

set searchTextField.textColor property of the UISearchBar to change the text color:

let searchBar = UISearchBar()
searchBar.searchTextField.textColor = .white

Or, for storyboard:

@IBOutlet weak var searchBar: UISearchBar!
searchBar.searchTextField.textColor = .white
-2

Swift 5 Xcode 11.4 iOS 13.4

    UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).textColor = .white
    UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).font = .systemFont(ofSize: 13)
blyscuit
  • 616
  • 7
  • 12