How to change UISearchBar Placeholder and image tint color?
Details
- Xcode Version 11.0 (11A420a), iOS 13, swift 5
Solution
import UIKitextension UISearchBar { func getTextField() -> UITextField? { return value(forKey: "searchField") as? UITextField } func set(textColor: UIColor) { if let textField = getTextField() { textField.textColor = textColor } } func setPlaceholder(textColor: UIColor) { getTextField()?.setPlaceholder(textColor: textColor) } func setClearButton(color: UIColor) { getTextField()?.setClearButton(color: color) } func setTextField(color: UIColor) { guard let textField = getTextField() else { return } switch searchBarStyle { case .minimal: textField.layer.backgroundColor = color.cgColor textField.layer.cornerRadius = 6 case .prominent, .default: textField.backgroundColor = color @unknown default: break } } func setSearchImage(color: UIColor) { guard let imageView = getTextField()?.leftView as? UIImageView else { return } imageView.tintColor = color imageView.image = imageView.image?.withRenderingMode(.alwaysTemplate) }}private extension UITextField { private class Label: UILabel { private var _textColor = UIColor.lightGray override var textColor: UIColor! { set { super.textColor = _textColor } get { return _textColor } } init(label: UILabel, textColor: UIColor = .lightGray) { _textColor = textColor super.init(frame: label.frame) self.text = label.text self.font = label.font } required init?(coder: NSCoder) { super.init(coder: coder) } } private class ClearButtonImage { static private var _image: UIImage? static private var semaphore = DispatchSemaphore(value: 1) static func getImage(closure: @escaping (UIImage?)->()) { DispatchQueue.global(qos: .userInteractive).async { semaphore.wait() DispatchQueue.main.async { if let image = _image { closure(image); semaphore.signal(); return } guard let window = UIApplication.shared.windows.first else { semaphore.signal(); return } let searchBar = UISearchBar(frame: CGRect(x: 0, y: -200, width: UIScreen.main.bounds.width, height: 44)) window.rootViewController?.view.addSubview(searchBar) searchBar.text = "txt" searchBar.layoutIfNeeded() _image = searchBar.getTextField()?.getClearButton()?.image(for: .normal) closure(_image) searchBar.removeFromSuperview() semaphore.signal() } } } } func setClearButton(color: UIColor) { ClearButtonImage.getImage { [weak self] image in guard let image = image, let button = self?.getClearButton() else { return } button.imageView?.tintColor = color button.setImage(image.withRenderingMode(.alwaysTemplate), for: .normal) } } var placeholderLabel: UILabel? { return value(forKey: "placeholderLabel") as? UILabel } func setPlaceholder(textColor: UIColor) { guard let placeholderLabel = placeholderLabel else { return } let label = Label(label: placeholderLabel, textColor: textColor) setValue(label, forKey: "placeholderLabel") } func getClearButton() -> UIButton? { return value(forKey: "clearButton") as? UIButton }}
Full Sample
import UIKitclass ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let searchBar = UISearchBar(frame: CGRect(x: 0, y: 20, width: UIScreen.main.bounds.width, height: 44)) searchBar.searchBarStyle = .default view.addSubview(searchBar) searchBar.placeholder = "placeholder" searchBar.set(textColor: .brown) searchBar.setTextField(color: UIColor.green.withAlphaComponent(0.3)) searchBar.setPlaceholder(textColor: .white) searchBar.setSearchImage(color: .white) searchBar.setClearButton(color: .red) }}
Result
If you have a custom image you could use, you can set the image and change the placeholder text color using something similar to the following:
[searchBar setImage:[UIImage imageNamed:@"SearchWhite"] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];UITextField *searchTextField = [searchBar valueForKey:@"_searchField"]; if ([searchTextField respondsToSelector:@selector(setAttributedPlaceholder:)]) { UIColor *color = [UIColor purpleColor]; [searchTextField setAttributedPlaceholder:[[NSAttributedString alloc] initWithString:@"Search" attributes:@{NSForegroundColorAttributeName: color}]];}
In that example I used purpleColor, instead you can use the + (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha
method to create your custom dark green color.
EDIT: I just realized you were writing it in swift... duh. Quickly typed this out so I didn't leave the answer in just Obj-C.
searchBar.setImage(UIImage(named: "SearchWhite"), forSearchBarIcon: UISearchBarIcon.Search, state: UIControlState.Normal); var searchTextField: UITextField? = searchBar.valueForKey("searchField") as? UITextField if searchTextField!.respondsToSelector(Selector("attributedPlaceholder")) { var color = UIColor.purpleColor() let attributeDict = [NSForegroundColorAttributeName: UIColor.purpleColor()] searchTextField!.attributedPlaceholder = NSAttributedString(string: "search", attributes: attributeDict) }
Swift 3.0
var searchTextField: UITextField? = searchBar.value(forKey: "searchField") as? UITextField if searchTextField!.responds(to: #selector(getter: UITextField.attributedPlaceholder)) { let attributeDict = [NSForegroundColorAttributeName: UIColor.white] searchTextField!.attributedPlaceholder = NSAttributedString(string: "Search", attributes: attributeDict) }
Swift 3: If you want to change the placeholder, clearbutton and magnifier glass
let textFieldInsideSearchBar = searchBar.value(forKey: "searchField") as? UITextField textFieldInsideSearchBar?.textColor = UIColor.white let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel textFieldInsideSearchBarLabel?.textColor = UIColor.white let clearButton = textFieldInsideSearchBar?.value(forKey: "clearButton") as! UIButton clearButton.setImage(clearButton.imageView?.image?.withRenderingMode(.alwaysTemplate), for: .normal) clearButton.tintColor = UIColor.white let glassIconView = textFieldInsideSearchBar?.leftView as? UIImageView glassIconView?.image = glassIconView?.image?.withRenderingMode(.alwaysTemplate) glassIconView?.tintColor = UIColor.white