Search code examples
iosswiftuitextfielduisearchbarios13

How to change text color of PlaceHolder in UISearchBar? (iOS 13)


After looking for updated (iOS 13) answers, I didn't find any solutions to this simple problem :

How to change the textColor of the placeholder in an UISearchBar ?

My app doesn't handle Light/Dark mode. I don't want the system to change my UIPlaceHolder text color. I want it to be always white.


    if #available(iOS 13.0, *) {
        let attrString = NSMutableAttributedString(string: "My PlaceHolder")
        attrString.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.white], range: NSRange(location: 0, length: attrString.length))
        searchController.searchBar.searchTextField.attributedPlaceholder = attrString
    }

I expected this code to work. I thought the new property searchTextField would have made it easier to customize my UISearchBar.

EDIT:

This code kind of works in the viewDidAppear method :

if #available(iOS 13.0, *) {
     searchController.searchBar.searchTextField.attributedPlaceholder = NSAttributedString(string: "My PlaceHolder", attributes: [NSAttributedString.Key.foregroundColor: UIColor.white.withAlphaComponent(0.80)])
 }

The issue is that the color is changing when you scroll up and down.


Solution

  • As you already mentioned, your code works only in viewDidAppear, which makes the placeholder to flicker from the default gray color to the preferred color.

    However, there seem to be a time before viewDidAppear (I couldn't figure it out when exactly), to change the placeholder before the view actually appears.

    I suppose, this may be connected to how iOS handles light/dark mode and/or an iOS bug.

    The solution I came out with that works around the issue:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    
        if #available(iOS 13.0, *) {
            let placeholder = NSAttributedString(string: "Search",
                                                 attributes: [
                                                    .foregroundColor: UIColor.white
            ])
            let searchTextField = searchBar.searchTextField
    
            // Key workaround to be able to set attributedPlaceholder
            DispatchQueue.global().async {
                DispatchQueue.main.async {
                    searchTextField.attributedPlaceholder = placeholder
                }
            }
        }
    }
    

    There seem to be no performance and/or other downside to this method.

    If anybody else comes with a better approach, feel free to collaborate.