59

I had been using the following code prior to iOS 11 to customize the appearance of the UISearchController search bar:

var searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.setDefaultSearchBar()
searchController.searchResultsUpdater = self

if #available(iOS 11.0, *) {
    navigationItem.searchController = searchController
} else {
    tableView.tableHeaderView = searchController.searchBar
}

extension UISearchBar {
    func setDefaultSearchBar() {
        self.tintColor = UIColor.blue
        self.searchBarStyle = .minimal
        self.backgroundImage = UIImage(color: UIColor.clear)
        let searchBarTextField = self.value(forKey: "searchField") as! UITextField
        searchBarTextField.textColor = UIColor.white
        searchBarTextField.tintColor = UIColor.blue
        searchBarTextField = .dark
    }
}

However, the appearance of the search bar fails to update when running the same code on iOS 11.

iOS 10:

enter image description here

iOS 11:

enter image description here

Much of the attention to this question so far has focused on the text color of the search bar. I am looking at more than this - the background color, tint color, the search indicator, clear button color, etc.

Alexander MacLeod
  • 2,026
  • 3
  • 14
  • 22
  • Well asked, but I cannot be surprised if, when you adopt the notion of the search field being handled through the navigation bar, the runtime imposes its own look upon it. You might be able to enforce your customizations by delaying them until after the runtime has had a chance to configure the search bar itself, but that's just a guess and it wouldn't surprise me if that didn't work either. – matt Aug 13 '17 at 18:10
  • You can achieve that kind of customisation using appearance proxies. However, in my experience it was buggy - The bar looks exactly as I want it to at first, but when another view controller hides it, it loses the rounded corners. – Andy Ibanez Aug 19 '17 at 20:54
  • Try apply font appearance to search field (white font color). – LLIAJLbHOu Aug 20 '17 at 21:22
  • Try by adding `searchController.searchBar.tintColor = UIColor.white` It should work. – Nishant Bhindi Aug 22 '17 at 13:18
  • Which version of iOS11 are you using? Have you did a complete clean of the Project? It may be a bug of the OS. However I will try to reproduce it and give you feedback soon...! @NishantBhindi he already does it... – Andrea Vultaggio Aug 24 '17 at 10:58
  • I am using the latest beta version of iOS 11 @AndreaVultaggio – Alexander MacLeod Aug 24 '17 at 15:59
  • try setting the navigationItem textColor – Wayne Aug 26 '17 at 14:04
  • Post an example project on GitHub, maybe you will get some more help that way. – Wayne Aug 26 '17 at 14:06
  • I have the same problems: https://stackoverflow.com/questions/45997996/ios-11-uisearchbar-in-uinavigationbar – Darko Sep 01 '17 at 20:45

9 Answers9

79

I just found out how to set them: (with some help of Brandon and Krunal, thanks!)

The "Cancel" text:

searchController.searchBar.tintColor = .white

The search icon:

searchController.searchBar.setImage(UIImage(named: "my_search_icon"), for: UISearchBarIcon.search, state: .normal)

The clear icon:

searchController.searchBar.setImage(UIImage(named: "my_search_icon"), for: UISearchBarIcon.clear, state: .normal)

The search text:

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

enter image description here

The placeholder:

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).attributedPlaceholder = NSAttributedString(string: "placeholder", attributes: [NSAttributedStringKey.foregroundColor: UIColor.white])

enter image description here

The white background:

if #available(iOS 11.0, *) {
    let sc = UISearchController(searchResultsController: nil)
    sc.delegate = self
    let scb = sc.searchBar
    scb.tintColor = UIColor.white
    scb.barTintColor = UIColor.white

    if let textfield = scb.value(forKey: "searchField") as? UITextField {
        textfield.textColor = UIColor.blue
        if let backgroundview = textfield.subviews.first {

            // Background color
            backgroundview.backgroundColor = UIColor.white

            // Rounded corner
            backgroundview.layer.cornerRadius = 10;
            backgroundview.clipsToBounds = true;
        }
    }

    if let navigationbar = self.navigationController?.navigationBar {
        navigationbar.barTintColor = UIColor.blue
    }
    navigationItem.searchController = sc
    navigationItem.hidesSearchBarWhenScrolling = false
}

enter image description here

Taken from here.

Darko
  • 9,655
  • 9
  • 36
  • 48
  • 4
    Again this answer isn’t great with colors. They navigation bar background color always seems darker than with what you specify. – Alexander MacLeod Sep 21 '17 at 13:59
  • Hi @AlexanderMacLeod , did you fix it? – sancho Sep 26 '17 at 15:09
  • 1
    Should be advised that, like through all of iOS dev, using any `value:forKey:` is considered accessing private api waters and would be most likely against Apple's t&c – Will Von Ullrich Sep 26 '17 at 20:55
  • 40
    WHY DOES APPLE BREAK THINGS EVERY RELEASE – hhanesand Oct 02 '17 at 16:36
  • 1
    This answer has almost saved me! Thanks! The only issue is that when you are pushing between view controllers, a black animated row appears instantly in the background of navigation area. – Konstantinos Oct 04 '17 at 01:40
  • @Konstantinos Im having the same issue, did you find a quick fix for this? – iruleonu Nov 07 '17 at 10:24
  • One issue with the white background code: a thin white line appears above the search field when pulling down the tableview. Does anyone has a solution for this? – Ely Nov 07 '17 at 15:39
  • @iruleonu unfortunately not, if you mean the "black animated row..." issue. – Konstantinos Nov 18 '17 at 23:59
  • @Konstantinos it turned out to be the background color of a parent view. (this search bar was on a UIViewController set as a root of a UINavigationController inside of a UITabBarController) – iruleonu Nov 19 '17 at 06:26
  • Another issue is the background color is not white but whiteish. I can't seem to get that changed in any way. Making my own implementation and living without the navigation integration. – Warpzit Jun 03 '19 at 08:26
  • I found a solution for the whiteish. The solution is to use searchBar.setSearchFieldBackgroundImage(backgroundImage, for: .normal) with an image that is transparent. If anyone need a solution pm me and I'll add it. – Warpzit Jun 03 '19 at 11:21
  • navigationbar.isTranslucent = false will also need for navigation bar – Amr Angry Feb 13 '20 at 07:10
  • Best answer! Tried dozens of methods and only this one worked – Alexei Mikhailov Jan 22 '21 at 13:37
11

To properly set the text typed into the search bar to white use (when using a dark field color):

searchController.searchBar.barStyle = .black

To set the textfield background color

if #available(iOS 11.0, *) {

        if let textfield = searchController.searchBar.value(forKey: "searchField") as? UITextField {
            if let backgroundview = textfield.subviews.first {

                // Background color
                backgroundview.backgroundColor = UIColor.white

                // Rounded corner
                backgroundview.layer.cornerRadius = 10;
                backgroundview.clipsToBounds = true;
            }
        }
    }

However using something like

textfield.textColor = UIColor.blue

in the above does not seem to work.

Zyntx
  • 659
  • 6
  • 19
6

Try setting the search bar's bar style.

searchController.searchBar.barStyle = UIBarStyleBlack;

image 1

Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Eddie Hsu
  • 61
  • 3
5

Moving the call to setDefaultSearchBar into viewDidAppear should fix this.

pronebird
  • 12,068
  • 5
  • 54
  • 82
4

You need to find the UISearchBar's underlying UITextField and change its text color.

Notice this only have effect when search controller is going to present (UISearchControllerDelegate.willPresentSearchController) or presented.

class ViewController : UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // setup your search controller...

        // set search controller's delegate
        navigationItem.searchController?.delegate = self
    }
}

extension ViewController : UISearchControllerDelegate {

    func willPresentSearchController(_ searchController: UISearchController) {
        // update text color
        searchController.searchBar.textField?.textColor = .white
    }
}

extension UISearchBar {

    var textField: UITextField? {
        for subview in subviews.first?.subviews ?? [] {
            if let textField = subview as? UITextField {
                return textField
            }
        }
        return nil
    }
}
Jonny
  • 1,969
  • 18
  • 25
3
    UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
Isa M
  • 159
  • 1
  • 10
  • Perhaps you could explain your answer a little more? Code-only answers are generally not the most useful. – Antimony Nov 14 '17 at 23:34
2

Try it: searchController.<YOUR SEARCHBAR>.barStyle = .blackOpaque instead of self.searchBarStyle = .minimal.

Thus:

var searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.setDefaultSearchBar()
//Add this line below
searchController.searchBar.barStyle = .blackOpaque
searchController.searchResultsUpdater = self

if #available(iOS 11.0, *) {
    navigationItem.searchController = searchController
} else {
    tableView.tableHeaderView = searchController.searchBar
}

extension UISearchBar {
    func setDefaultSearchBar() {
        self.tintColor = UIColor.blue
        //Delete this line below
        self.searchBarStyle = .minimal
        self.backgroundImage = UIImage(color: UIColor.clear)
        let searchBarTextField = self.value(forKey: "searchField") as! UITextField
        searchBarTextField.textColor = UIColor.white
        searchBarTextField.tintColor = UIColor.blue
        searchBarTextField = .dark
    }
}
xskxzr
  • 12,442
  • 12
  • 37
  • 77
Hoff Silva
  • 51
  • 4
1

If you need to change the background colour of the textField in the searchBar, see my answer here: https://stackoverflow.com/a/46315974/1109892

Adam Studenic
  • 2,115
  • 2
  • 25
  • 22
0

You have to access the UITextField inside the UISearchBar. You can do that by using

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

textFieldInsideSearchBar?.textColor = yourcolor

OR

enter image description here

yogesh wadhwa
  • 711
  • 8
  • 16
  • Probably You got clear tint color, it's the only reason I could imaging try to set "_searchBar.tintColor = [UIColor redColor];" – yogesh wadhwa Aug 24 '17 at 07:46