Please take a look at this code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.obscuresBackgroundDuringPresentation = NO;
self.navigationItem.searchController = self.searchController;
self.definesPresentationContext = YES;
self.searchController.searchBar.placeholder = NSLocalizedString(#"Search", #"search placeholder");
self.searchController.searchBar.searchTextField.backgroundColor = [UIColor redColor];
}
Looks pretty simple. I'm trying to set red background color to UISearchTextField. But unfortunately the result color is not precisely red. When I check the color with ColorSync utility it shows RGB as 0.9255, 0.0, 0.0667 which is not what I need. Of course red is just a simplified example. It applies to any color. Actually I need to set a color with precise RGB and unable to do so. Obviously iOS applies some tint to the search bar somehow. What I tried was: applying clear color as tint to the search bar and text field along with setting background image but all in vain. This little tint never goes away. Any ideas, guys? How do I set a precise color?
Here is the solution it will help you
import UIKit
extension UISearchBar {
func getTf() -> UITextField? { return value(forKey: "searchField") as? UITextField }
func setTf(color: UIColor) {
guard let tf = getTf() else { return }
switch searchBarStyle {
case .minimal:
tf.layer.backgroundColor = color.cgColor
tf.layer.cornerRadius = 2
case .prominent:
break,
default:
tf.backgroundColor = color
#unknown
default: break
}
}
}
For Usage
searchBar.searchBarStyle = .minimal
func configureSearchController()
{
resultsController.tableView.delegate = self
resultsController.tableView.dataSource = self
self.searchController = UISearchController(searchResultsController: self.resultsController)
//self.tableView.tableHeaderView = self.searchController.searchBar
self.searchController.searchResultsUpdater = self
self.searchController.dimsBackgroundDuringPresentation = false
self.searchController.searchBar.sizeToFit()
searchController.searchBar.delegate = self
self.searchController.searchBar.scopeButtonTitles = []
for subView in searchController.searchBar.subviews {
for subViewOne in subView.subviews {
if subViewOne is UITextField {
searchTextField = subViewOne as! UITextField
subViewOne.backgroundColor = UIColor.white
var currentTextFieldBounds = subViewOne.bounds
currentTextFieldBounds.size.height = 45
subViewOne.bounds = currentTextFieldBounds
break
}
}
}
extendedLayoutIncludesOpaqueBars = true
definesPresentationContext = true
}
This doesn't change height of text field unexpectedly. I also want to change height of search bar. What changes should I make here for the same to work?
IMO, The search bar size shouldn't be changed as it's the native standard provided by Apple. Also the way you use of recursively searching of textfield is not recommended and not guaranteed to work in all iOS versions.
Maybe you can try to use custom Search bar with your own text field and u can easily play with it.
I'm trying to add a UISearchController to a UIViewController that contains a UITableView (and an MKMapView too, but hopefully that's not the problem). I followed Ray Wenderlich's tutorial but I can't get the same result in terms of behaviour.
Here is my viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// Setup the Search Controller
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = NSLocalizedString("Search references by project, customer or city", comment: "")
if #available(iOS 11.0, *) {
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = true
} else {
tableView.tableHeaderView = searchController.searchBar
}
definesPresentationContext = true
self.modeSelector.layer.cornerRadius = 5.0
if let split = splitViewController {
let controllers = split.viewControllers
detailViewController = (controllers[controllers.count - 1] as! UINavigationController).topViewController as? ReferenceViewController
}
self.navigationItem.rightBarButtonItem?.isEnabled = false
}
Note that the #available test in the middle is because I need to support iOS up to 9.1.
Now I see several problems:
The search bar appears right away and I can't hide it by scrolling
When I focus the search bar, the top of the tableview doesn't stick to the bottom of the navigation item:
The only major difference I see with Ray Wenderlich's sample project is that since I created my project with Xcode 9, my storyboard doesn't use top and bottom layout guides, but safe areas. Don't know if it's relevant, but that's the only thing I see.
Any idea what's going on and how I could fix this?
If you need to support iOS up to 9.1, you probably use emulator with version older than 9.1. Therefore, "maybe" obscuresBackgroundDuringPresentation doesn't affect the searchController properly, since it's only available on iOS 9.1 or newer. Add dimsBackgroundDuringPresentation to support up to 9.1:
if #available(iOS 9.1, *) {
searchController?.obscuresBackgroundDuringPresentation = false
} else {
searchController?.dimsBackgroundDuringPresentation = false
}
If this doesn't help to display as expected, I'm almost sure that the problem is about your layout constraints. Please add your current constraints if you couldn't bring your layout in compliance with safe area.
use this below line of code into your viewDidload
self.navigationController?.navigationBar.isTranslucent = false
Hope this will help you
If you are using xcode 9 (ios 11). Then the thing you really want to do is -
Use the new Broader navigation bars which are the new highlights in the ios 11 devices. But as there are many who have not shifted to ios-11, previous version devices are also taken into consideration.
For adding the search bar to the newer navigation bars I have used the following function which gives a search bar on scrolling and hides it when user scrolls the page.
func addSearchBar() {
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
//Change the colors as you like them
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.white
}
navigationItem.searchController = sc
navigationItem.hidesSearchBarWhenScrolling = true
}else{
//add the logic for previous version devices here.
}
I have also set the
self.navigationController?.navigationBar.prefersLargeTitles = true; in viewDidLoad as there is a bug in xcode9 and setting it from the interface builder does not work(yet).
The following method has been taken from here
I have a requirement in which I have to use a UINavigationBar with a red large title.
Currently, I have the following code:
func prepareNavigationController() {
let navController = UINavigationController(rootViewController: self)
navController.navigationBar.prefersLargeTitles = true
navigationItem.searchController = UISearchController(searchResultsController: nil)
navigationItem.hidesSearchBarWhenScrolling = false
navController.navigationBar.titleTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.red]
}
But it's not actually tinting the title label to red. This is the result:
But changing prefersLargeTitles to false does the right thing, and my title is red.
navController.navigationBar.prefersLargeTitles = false
I am not entirely sure if this is a bug since at the time of this writing we are still in the first beta, or if this is intentional behavior, mostly because I haven't any of Apple's apps color the large titles before. Is there any way to actually get the large title to have any color I want?
There is a new UINavigationBar property "largeTitleTextAttribute" that should help with this.
largeTitleTextAttribute
Here is a sample code you can add to your view controllers viewDidLoad method
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.blue]
Here is a sample code and screenshot without the largeTitleTextAttributes set, but the barStyle is set to .black
navigationController?.navigationBar.barStyle = .black
Here is a screenshot without the largeTitleTextAttributes set, but the barStyle is set to .default
navigationController?.navigationBar.barStyle = .default
The way you do this in iOS 13 has changed, you now use UINavigationBarAppearance class like this…
let appearance = UINavigationBarAppearance(idiom: .phone)
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.systemRed]
appearance.titleTextAttributes = [.foregroundColor: UIColor.systemRed]
appearance.backgroundColor = .white
navigationItem.standardAppearance = appearance
navigationItem.scrollEdgeAppearance = appearance
Not sure if it's a bug in beta 1 & 2, but here is a way to set the color. It's a bit of a "hacky" workaround, but it should work until Apple fixes this. In both the Objective-C and Swift version, this code goes in the viewDidAppear: method.
Objective-C:
dispatch_async(dispatch_get_main_queue(), ^{
for (UIView *view in self.navigationController.navigationBar.subviews) {
NSArray <__kindof UIView *> *subviews = view.subviews;
if (subviews.count > 0) {
UILabel *label = subviews[0];
if (label.class == [UILabel class]) {
[label setTextColor:[UIColor redColor]];
}
}
}
});
Swift:
DispatchQueue.main.async {
for view in self.navigationController?.navigationBar.subviews ?? [] {
let subviews = view.subviews
if subviews.count > 0, let label = subviews[0] as? UILabel {
label.textColor = UIColor.red
} } }
If using storyboard, just change "Large Title Text Attributes" Title Color at Navigation Bar Attribute Inspector:
Here's the working code to use large titles and sets the text color of small and large titles to white, both on iOS11+ and on older iOS versions.
// Will apply to versions before iOS 11
navigationController?.navigationBar.titleTextAttributes = [
NSAttributedStringKey.foregroundColor: UIColor.white
]
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.largeTitleTextAttributes = [
NSAttributedStringKey.foregroundColor: UIColor.white
]
}
(There used to be a bug in Xcode, but it now appears to be fixed)
Has anyone any idea or code sample on how can I change the text color of the placeholder text of a UISearchBar?
for iOS5+ use the appearance proxy
[[UILabel appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor redColor]];
Found the answer from Change UITextField's placeholder text color programmatically
// Get the instance of the UITextField of the search bar
UITextField *searchField = [searchBar valueForKey:#"_searchField"];
// Change search bar text color
searchField.textColor = [UIColor redColor];
// Change the search bar placeholder text color
[searchField setValue:[UIColor blueColor] forKeyPath:#"_placeholderLabel.textColor"];
First solution is OK, but if you use multiple UISearchBar, or create a lot of instances it may fail. The one solution that always work for me is to use also appearance proxy but directly on UITextField
NSDictionary *placeholderAttributes = #{
NSForegroundColorAttributeName: [UIColor darkButtonColor],
NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue" size:15],
};
NSAttributedString *attributedPlaceholder = [[NSAttributedString alloc] initWithString:self.searchBar.placeholder
attributes:placeholderAttributes];
[[UITextField appearanceWhenContainedInInstancesOfClasses:#[[UISearchBar class]]] setAttributedPlaceholder:attributedPlaceholder];
Here is a Solution for Swift:
Swift 2
var textFieldInsideSearchBar = searchBar.valueForKey("searchField") as? UITextField
textFieldInsideSearchBar?.textColor = UIColor.whiteColor()
var textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.valueForKey("placeholderLabel") as? UILabel
textFieldInsideSearchBarLabel?.textColor = UIColor.whiteColor()
Swift 3
let textFieldInsideSearchBar = searchBar.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.textColor = UIColor.white
let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel
textFieldInsideSearchBarLabel?.textColor = UIColor.white
Try this and see: (I tested below code with Swift 4.1 - Xcode 9.3-beta4)
#IBOutlet weak var sbSearchBar: UISearchBar!
if let textfield = sbSearchBar.value(forKey: "searchField") as? UITextField {
textfield.backgroundColor = UIColor.yellow
textfield.attributedPlaceholder = NSAttributedString(string: textfield.placeholder ?? "", attributes: [NSAttributedStringKey.foregroundColor : UIColor.red])
textfield.textColor = UIColor.green
if let leftView = textfield.leftView as? UIImageView {
leftView.image = leftView.image?.withRenderingMode(.alwaysTemplate)
leftView.tintColor = UIColor.red
}
}
Here is result:
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
if let textFieldInsideSearchBar = searchBar.value(forKey: "searchField") as ? UITextField {
textFieldInsideSearchBar ? .textColor = UIColor.white
if let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as ? UILabel {
textFieldInsideSearchBarLabel ? .textColor = UIColor.white
if 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
}
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.
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 = ""
}
Swift 3
UILabel.appearance(whenContainedInInstancesOf: [UISearchBar.self]).textColor = UIColor.white
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...
Try this:
[self.searchBar setValue:[UIColor whatever] forKeyPath:#"_searchField._placeholderLabel.textColor"];
You can also set this in storyboard, select search bar, add entry under User Defined Runtime Attributes:
_searchField._placeholderLabel.textColor
of type Color and select the color you need.
worked for me on IOS 13
searchBar.searchTextField.attributedPlaceholder = NSAttributedString(
string: "Search something blabla",
attributes: [.foregroundColor: UIColor.red]
)
After surveyed a couple of answers, I come out this, hope its help
for (UIView *subview in searchBar.subviews) {
for (UIView *sv in subview.subviews) {
if ([NSStringFromClass([sv class]) isEqualToString:#"UISearchBarTextField"]) {
if ([sv respondsToSelector:#selector(setAttributedPlaceholder:)]) {
((UITextField *)sv).attributedPlaceholder = [[NSAttributedString alloc] initWithString:searchBar.placeholder attributes:#{NSForegroundColorAttributeName: [UIColor whiteColor]}];
}
break;
}
}
}
This solution works on Xcode 8.2.1. with Swift 3.0. :
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
}
}
Usage example:
searchController.searchBar.setPlaceholderTextColorTo(color: mainColor)
This is an old question, but for anyone stumbling on it nowadays, you can change the search icon on iOS 8.x - 10.3 using the following:
[_searchBar setImage:[UIImage imageNamed:#"your-image-name"] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
Regarding the placeholder text color, you may check my other answer, which uses a Category, here: UISearchBar change placeholder color
Try this:
UITextField *searchField = [searchbar valueForKey:#"_searchField"];
field.textColor = [UIColor redColor]; //You can put any color here.