UISearchBar change placeholder color

Viewed 46072

Has anyone any idea or code sample on how can I change the text color of the placeholder text of a UISearchBar?

18 Answers

Swift 5 - ios 13:

Those who are stuck let me tell you it is going to work only in viewDidLayoutSubviews not in viewDidLoad

override func viewDidLayoutSubviews() {

    setupSearchBar(searchBar: YourSearchBar)

}

    func setupSearchBar(searchBar : UISearchBar) {

    searchBar.setPlaceholderTextColorTo(color: UIColor.white)        

   }

extension UISearchBar
{
    func setPlaceholderTextColorTo(color: UIColor)
    {
        let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
        textFieldInsideSearchBar?.textColor = color
        let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel
        textFieldInsideSearchBarLabel?.textColor = color
    }
}

Happy coding :)

It looks like Apple does not want us to play with the placeholder colors when it comes to UISearchBar class. So, let's create our own placeholder label!

  • No subclassing.
  • Works with iOS 13 SDK.
  • Just one innocent workaround.

enter image description here

let searchBar = searchController.searchBar
// ...
// Configure `searchBar` if needed
// ...

let searchTextField: UITextField
if #available(iOS 13, *) {
    searchTextField = searchBar.searchTextField
} else {
    searchTextField = (searchBar.value(forKey: "searchField") as? UITextField) ?? UITextField()
}

// Since iOS 13 SDK, there is no accessor to get the placeholder label.
// This is the only workaround that might cause issued during the review.
if let systemPlaceholderLabel = searchTextField.value(forKey: "placeholderLabel") as? UILabel {
    // Empty or `nil` strings cause placeholder label to be hidden by the search bar
    searchBar.placeholder = " "

    // Create our own placeholder label
    let placeholderLabel = UILabel(frame: .zero)

    placeholderLabel.text = "Search"
    placeholderLabel.font = UIFont.systemFont(ofSize: 17.0, weight: .regular)
    placeholderLabel.textColor = UIColor.blue.withAlphaComponent(0.5)

    systemPlaceholderLabel.addSubview(placeholderLabel)

    // Layout label to be a "new" placeholder
    placeholderLabel.leadingAnchor.constraint(equalTo: systemPlaceholderLabel.leadingAnchor).isActive = true
    placeholderLabel.topAnchor.constraint(equalTo: systemPlaceholderLabel.topAnchor).isActive = true
    placeholderLabel.bottomAnchor.constraint(equalTo: systemPlaceholderLabel.bottomAnchor).isActive = true
    placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
    placeholderLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
} else {
    searchBar.placeholder = ""
}

It is easy from iOS 13.0 onwards, You can simply use searchTextField property of a search bar to update attributed properties of the placeholder.

self.searchController.searchBar.searchTextField.attributedPlaceholder =  NSAttributedString.init(string: "Search anything...", attributes: [NSAttributedString.Key.foregroundColor:UIColor.red])

One line solution

iOS 13

Previous solutions may not work on iOS 13 because new searchTextField has been added, and you can set attributed string on it.

I wrapped that into category:

@interface UISearchBar (AttributtedSetter)
- (void)setThemedPlaceholder:(NSString*)localizationKey;
@end

@implementation UISearchBar (AttributtedSetter)

- (void)setThemedPlaceholder:(NSString*)localizationKey {
    ThemeObject *currentTheme = [[ThemeManager standardThemeManager] currentTheme];
    self.searchTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:NSLocalizedString(localizationKey, @"") attributes:@{NSForegroundColorAttributeName : currentTheme.colorSearchBarText}];
}

@end

iOS 13

Use a custom search bar subclass.

This also works when part of a UISearchController inside a UINavigationItem (with hidesSearchBarWhenScrolling = true).

We want to apply our changes immediately after UIAppearance proxies are being applied since those are the most likely root cause:

class MySearchBar : UISearchBar {
    // Appearance proxies are applied when a view is added to a view hierarchy, so apply your tweaks after that:
    override func didMoveToSuperview() {
        super.didMoveToSuperview() // important! - system colors will not apply correctly on ios 11-12 without this

        let placeholderColor = UIColor.white.withAlphaComponent(0.75)
        let placeholderAttributes = [NSAttributedString.Key.foregroundColor : placeholderColor]
        let attributedPlaceholder = NSAttributedString(string: "My custom placeholder", attributes: placeholderAttributes)
        self.searchTextField.attributedPlaceholder = attributedPlaceholder
        
        // Make the magnifying glass the same color
        (self.searchTextField.leftView as? UIImageView)?.tintColor = placeholderColor
    }
}

// Override `searchBar` as per the documentation
private class MySearchController : UISearchController {
    private lazy var customSearchBar = MySearchBar()
    override var searchBar: UISearchBar { customSearchBar }
}

That took quite some time to get working properly...

worked for me on IOS 13

searchBar.searchTextField.attributedPlaceholder = NSAttributedString(
    string: "Search something blabla",
    attributes: [.foregroundColor: UIColor.red]
)
Related