6

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.

Dejan Skledar
  • 11,280
  • 7
  • 44
  • 70
Funnycuni
  • 369
  • 1
  • 15
  • Hi. Maybe this topic will help you https://stackoverflow.com/questions/28499701/how-can-i-change-the-uisearchbar-search-text-color. Answer https://stackoverflow.com/a/28499827/9048325 – Vladyslav Shmatok Oct 08 '19 at 13:45
  • 1
    I have already read it. Only 1 answer mention iOS 13, and it's just an extension to access the searchTextField property. – Funnycuni Oct 08 '19 at 13:47

3 Answers3

3

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.

Dejan Skledar
  • 11,280
  • 7
  • 44
  • 70
0

you can set this with UITextField appearance property. check this line of code

 UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]
Ashish
  • 706
  • 8
  • 22
0

I guess the reason why it doesn't work is probably the searchController.searchBar.searchTextField = nil you got.

searchTextField is a new property for iOS 13, which can be done if you only support >= iOS 13. If you want to adapt to the previous version of iOS 13, you can traverse UISearchBar to find UISearchBarTextField and directly set the found UISearchBarTextField.

The code I looked up is probably like this, I put it in the Category of UIView.

- (UIView *)findChildViewClass:(Class)childViewClass fromView:(UIView *)fromView{
    for (UIView *subView in fromView.subviews) {
        if ([subView isMemberOfClass:childViewClass]) {
            return subView;
        }
        UIView *finalView = [self findChildViewClass:childViewClass fromView:subView];
        if (finalView) {
            return finalView;
        }else{
            continue;
        }
    }
    return nil;
}

When used, you can customize a searchTextField property to inherit from UITextField to save the found value.

_searchTextField = (UITextField *)[searchBar findChildViewClass:NSClassFromString(@"UISearchBarTextField") fromView: searchBar];

This is what I use now, it is working, I hope to be useful to you.

Nullable
  • 761
  • 5
  • 17