UISearchBar change placeholder color - ios

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.

Related

Wrong placement of search text field inside search bar on iOS 11

I am using UISearchController as part of navigation bar using the new APIs introduced in iOS 11. I am using it in the following manner in my ViewController's viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
[_table setDataSource:self];
[_table setDelegate:self];
searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
[self.navigationItem setSearchController:searchController];
[self.navigationItem setHidesSearchBarWhenScrolling:NO];
[searchController.searchBar setBackgroundColor:[UIColor greenColor]];
}
However, the search text field is rendered at the wrong position inside the search bar. Look at the following screenshot.
https://imgur.com/a/Igf49
I inspected the view hierarchy and found that UISearchBarTextField object (which is not accessible directly to devs) in the search bar has a frame.y value of 1 which is probably causing this issue. I have tested this on iOS 11 beta 10 and iOS 11 GM.
Is this a known issue? Is there any fix for this? Or is it something I am doing wrong on my end?
Any help will be appreciated (:
Here's code which shows how to change the background colour of textField in searchBar on iOS 11.
Before:
After:
Obj-C: in (void)viewDidLoad use this code:
if (#available(iOS 11, *)) {
UITextField *textField = [self.searchController.searchBar valueForKey:#"searchField"];
UIView *backgroundView = textField.subviews.firstObject;
backgroundView.backgroundColor = UIColor.whiteColor;
backgroundView.layer.cornerRadius = 10;
backgroundView.clipsToBounds = YES;
}
Swift: in viewDidLoad() use this code:
if #available(iOS 11.0, *) {
if let textfield = scb.value(forKey: "searchField") as? UITextField {
textfield.textColor = UIColor.blue
if let backgroundview = textfield.subviews.first {
backgroundview.backgroundColor = UIColor.white
backgroundview.layer.cornerRadius = 10;
backgroundview.clipsToBounds = true;
}
}
}
You image (exact problem) is not accessible. So can see exact problem. But from your statement, I found your problem. I tried following for iOS 11 and its working fine.
My code has a solution to your problem but it is in Swift. You need to convert it into Objective-C. It won't be hard for you to do it.
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 = 5;
backgroundview.clipsToBounds = true;
}
}
if let navigationbar = self.navigationController?.navigationBar {
navigationbar.barTintColor = UIColor.blue
}
navigationItem.searchController = sc
navigationItem.hidesSearchBarWhenScrolling = false
}
Output:

Customize the searchController of navigationItem , but doesn't work with iOS 11

I have searched the similar question UISearchController iOS 11 customizationbut al the methods in the comments couldn't help me out.So I want to ask it again.
I used the following codes to set the appearance of the searchBar.
Extension the UISearchBr to get the textField and placeHolderLabel:
extension UISearchBar{
var textField: UITextField?{
if let textField = self.value(forKey: "searchField") as? UITextField {
return textField
}
return nil
}
var placehloderLabel:UILabel?{
if let placeholderLabel = textField?.value(forKey: "placeholderLabel") as? UILabel{
return placeholderLabel
}
return nil
}
}
Customize a subclass of UISearchController:
class CustomSearchController:UISearchController{
override init(searchResultsController: UIViewController?) {
super.init(searchResultsController: searchResultsController)
self.definesPresentationContext = true
self.dimsBackgroundDuringPresentation = false
self.hidesNavigationBarDuringPresentation = true
self.searchBar.searchBarStyle = .minimal
self.searchBar.placeholder = "搜索歌单内歌曲"
self.searchBar.textField?.textColor = UIColor.white
self.searchBar.placehloderLabel?.textColor = .white
self.searchBar.placehloderLabel?.font = UIFont.systemFont(ofSize: 15)
}
Set prefersLargeTitles UINavigationBar.appearance().prefersLargeTitles = true
If navigationItem.searchController = searchController and the result is as follows (the appearance of the searchBar DOESN'T make change):
But if I set navigationItem.titleView = searchController.searchBar,it makes:
Does the iOS 11 permit developers to change the searchBar's
appearance?If yes,I wonder how to customize it ?Any
point is appreciated.Thanks!
Working with color and UINavigationItem's search controller
This code is in the AppDelegate class.
UISearchBar.appearance().tintColor = UIColor(named: "Button") // using this to set the text color of the 'Cancel' button since the search bar ignores the global tint color property for some reason
if #available(iOS 11.0, *) {
// Search bar placeholder text color
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).attributedPlaceholder = NSAttributedString(string: "Search", attributes: [NSForegroundColorAttributeName: UIColor.white])
// Search bar text color
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSForegroundColorAttributeName: UIColor.red]
// Insertion cursor color
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = UIColor.red
} else {
// Fallback on earlier versions
}
// Search bar clear icon
UISearchBar.appearance().setImage(UIImage(named: "clear"), for: .clear, state: .normal)

Changing the text color of a navigation bar title when "prefersLargeTitles" is set to true

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)

UITextField placeholder text: adjust to fit

I have UITextField with longer text in it set as placeholder. What I want is for this placeholder text to adjust its font size when the width of field is too small.
I already tried this solution described in other posts (programmatically and in IB)
self.fieldTest.adjustsFontSizeToFitWidth = true
self.fieldTest.minimumFontSize = 10.0
What am I missing here?
You can create a subclass of UITextField:
class AutoSizeTextField: UITextField {
override func layoutSubviews() {
super.layoutSubviews()
for subview in subviews {
if let label = subview as? UILabel {
label.minimumScaleFactor = 0.3
label.adjustsFontSizeToFitWidth = true
}
}
}
}
Or you can just add some code in your view controller's viewDidAppear:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
for subview in fieldTest.subviews {
if let label = subview as? UILabel {
label.minimumScaleFactor = 0.3
label.adjustsFontSizeToFitWidth = true
}
}
}
Here you go :
_myTextField.placeholder = #"SomeTextSomeTextSome";
UILabel *label = [_myTextField valueForKey:#"_placeholderLabel"];
label.adjustsFontSizeToFitWidth = YES;
Cheers!!
Based on answer 9: in Storyboard go to the identity inspector tab of the text field element, and under the "User Defined Runtime Attributes" section, add the following:
Here's a solution that depends on the undocumented fact that the UITextField has a child UILabel (actually UITextFieldLabel) to render the placeholder. The advantage of this solution over some others is that it degrades gracefully should Apple's implementation change. It also doesn't make assumptions about the existence of undocumented ivars.
Basically we extend UILabel via a category. If we see ourselves being parented to a UITextField then we turn on adjustFontSizeToFitWidth.
#interface UILabel (TS)
#end
#implementation UILabel (TS)
- (void) didMoveToSuperview
{
[super didMoveToSuperview];
if ( [self.superview isKindOfClass: [UITextField class]] ) {
self.adjustsFontSizeToFitWidth = YES;
}
}
#end
After reviewing the class reference for UITextField's, it seems that adjustsFontSizeToFitWidth only affects the the text property of the UITextField and not the placeholder property. While I don't know off the top of my head a way to get the placeholder to respond to adjustsFontSizeToFitWidth, I can suggest two hacky ideas that may give you the appearance that you want. Just be aware that I'm not near a Mac right now so I haven't tested these ideas:
1:
Since a placeholder is just text with a 70% gray color, you could set the label's text property to be whatever you need it to be, and then implement the UITextFieldDelegate's textFieldShouldBeginEditing method to clear the text and change the color back to normal. You would also have to implement the textFieldShouldClear and textFieldDidEndEditing methods to replace the pseudo-placeholder back in the UITextField and change the text color back to 70% gray.
2:
In viewWillAppear you could set the UITextField's text to what your placeholder should be, create a UIFont object and set it equal to the UITextField's font property, clear the UITextField's text, and set the placeholder to be an NSAttributedString with the font object as a property. Here's an example of what I mean:
-(void)viewWillAppear:(BOOL) animated {
[super viewWillAppear:animated];
someTextField.adjustsFontSizeToFitWidth = YES;
someTextField.text = #"placeholderText";
UIFont *font = someTextField.font;
someTextField.text = nil;
NSDictionary *attributes = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
NSAttributedString *placeholderString= [[NSAttributedString alloc] initWithString:#"placeholderText" attributes:attributes];
someTextField.placeholder = placeholderString;
}
Edit: Just noticed the swift tag. I wrote my code in Objective-C, but you should be able to easily translate it to Swift.
Try using attributed placeholder instead of normal place holder
Try this
let attributedplaceholder = NSAttributedString(string: "placeholdertext", attributes: [NSFontAttributeName: UIFont(name: "FontName", size: 10)!])
self.fieldTest.attributedPlaceholder = attributedplaceholder
You can add additional attributes to the placeholder like textcolor and other
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
for subView in fieldTest.subviews{
if subView .isKind(of: UILabel.self){
let label = subView as! UILabel
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.2
}
}
}
Swift
Feel free to improve the extension - pretty sure there is a more elegant way to iterate over the subviews.
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tfCountryCode.allSubviewsOfClass(UILabel.self).forEach {
$0.adjustsFontSizeToFitWidth = true
$0.minimumScaleFactor = 0.5
}
}
extension UIView {
func allSubviewsOfClass<K: UIView>(_ clazz: K.Type) -> [K] {
var matches = [K]()
if subviews.isEmpty { return matches }
matches.append(contentsOf: subviews.filter { $0 is K } as! [K])
let matchesInSubviews = subviews.flatMap { return $0.allSubviewsOfClass(clazz) }
matches.append(contentsOf: matchesInSubviews.flatMap { $0 })
return matches
}
}
My solution:
if let label = yourTextField.value(forKey: "placeholderLabel") as? UILabel {
label.adjustsFontSizeToFitWidth = true
}
And don't forget this:
yourTextField.minimumFontSize = 10 // 10 is an example, pass your minimumFontSize
Tested and run perfectly.
You can use these two solution:
1.If You have fixed font size if Textfield size is less than placeholder text:
let placeholderString = testTF.placeholder
print(placeholderString!)
let font = UIFont(name: (testTF.font?.fontName)!, size: 16)!
let fontAttributes = [NSFontAttributeName: font]
let size = (placeholderString! as NSString).sizeWithAttributes(fontAttributes)
print(size)
print(testTF.frame.size.width)
if(size.width > testTF.frame.size.width)
{
let font = UIFont(name: (testTF.font?.fontName)!, size: 4)!
let attributes = [
NSForegroundColorAttributeName: UIColor.lightGrayColor(),
NSFontAttributeName : font]
testTF.attributedPlaceholder = NSAttributedString(string: placeholderString!,
attributes:attributes)
}
else
{
let attributes = [
NSForegroundColorAttributeName: UIColor.lightGrayColor(),
NSFontAttributeName : font]
testTF.attributedPlaceholder = NSAttributedString(string: placeholderString!,
attributes:attributes)
}
2) If you want dynamic font size than you just check the above condition for width of textfield and placeholder text size.width. if the placeholder text size is greater than textfield size than create one label inside the textfield and set minimum font on that.
if(size.width > testTF.frame.size.width)
{
placeholder = UILabel(frame: CGRect( x: 0, y: 0, width: testTF.bounds.width, height: testTF.bounds.height))
placeholder.text = placeholderString
placeholder.numberOfLines = 1;
//placeholder.minimumScaleFactor = 8;
placeholder.adjustsFontSizeToFitWidth = true
placeholder.textColor = UIColor.grayColor()
placeholder.hidden = !testTF.text!.isEmpty
placeholder.textAlignment = .Center
testTF.addSubview(placeholder)
}
In Swift
yourTextField.subviews
.filter { $0 is UILabel }
.flatMap { $0 as? UILabel }
.forEach {
$0.adjustsFontSizeToFitWidth = true
$0.minimumScaleFactor = 0.5
}
it works :)
Try this: It's working fine without any issues:
yourTextField.placeholder = "Adjust placeHolder text for textFields iOS"
let label = yourTextField.value(forKey: "_placeholderLabel") as? UILabel
label?.adjustsFontSizeToFitWidth = true
The whole approach or shrinking font size to fit is misguided in the day and age of accessibility.
Firstly you have zero business specifying text size in the first place, let alone shrinking that further: you have to rely on the accessibility API.
Thus if the placeholder is likely to not fit it has to be placed
as a UILabel preceding the UITextField. The placeholders are supposed to be SHORT and fit without clippage.
To determine if it's clipped I guess you could use - (CGRect)placeholderRectForBounds:(CGRect)bounds; but then you are in
murky waters of using an API which Apple says you should only override (but not call yourself even though it's probably meaningful and safe
within the confines of didlayoutsubviews method[s])
If placeholder text is dynamic (server served) dump it into a UILabel.

How to change the color of the UISearchBar Icon?

I don't know how to modify the original searchIcon's color.
The searchIcon is located in the leftView of the searchTextField. Since this is accessible we can easily set the tintColor for the view. The tintColor is also used for the searchIcon.
So in your code you can change the search icon to white with the following code:
searchBar.searchTextField.leftView?.tintColor = .white
Best solution I found was here
Changing the color of the icons in a UItextField inside a UISearchBar
(This solution uses the original UISearchBar's icon, no need to supply your own graphical asset)
Converted to Swift (Swift 3):
if let textFieldInsideSearchBar = self.searchBar.value(forKey: "searchField") as? UITextField,
let glassIconView = textFieldInsideSearchBar.leftView as? UIImageView {
//Magnifying glass
glassIconView.image = glassIconView.image?.withRenderingMode(.alwaysTemplate)
glassIconView.tintColor = .whiteColor
}
You can use a custom image of a white search icon, as the search bar will not modify your supplied image. To set a custom image, use this method. (Link to documentation.)
- (void)setImage:(UIImage *)iconImage
forSearchBarIcon:(UISearchBarIcon)icon
state:(UIControlState)state;
Example Code:
[searchBar setImage:[UIImage imageNamed:#"SearchIcon"]
forSearchBarIcon:UISearchBarIconSearch
state:UIControlStateNormal];
In Swift:
searchBar.setImage(UIImage(named: "SearchIcon"), for: .search, state: .normal)
This soultion worked for me on Xcode 8.2.1 in 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
}
func setMagnifyingGlassColorTo(color: UIColor)
{
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let glassIconView = textFieldInsideSearchBar?.leftView as? UIImageView
glassIconView?.image = glassIconView?.image?.withRenderingMode(.alwaysTemplate)
glassIconView?.tintColor = color
}
}
Usage example:
searchController.searchBar.setPlaceholderTextColorTo(color: mainColor)
searchController.searchBar.setMagnifyingGlassColorTo(color: mainColor)
Swift-3:
extension UISearchBar
{
func setMagnifyingGlassColorTo(color: UIColor)
{
// Search Icon
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let glassIconView = textFieldInsideSearchBar?.leftView as? UIImageView
glassIconView?.image = glassIconView?.image?.withRenderingMode(.alwaysTemplate)
glassIconView?.tintColor = color
}
func setClearButtonColorTo(color: UIColor)
{
// Clear Button
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let crossIconView = textFieldInsideSearchBar?.value(forKey: "clearButton") as? UIButton
crossIconView?.setImage(crossIconView?.currentImage?.withRenderingMode(.alwaysTemplate), for: .normal)
crossIconView?.tintColor = color
}
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
}
}
Call these extension method like this:
searchBarTextField.setMagnifyingGlassColorTo(color: yourColor)
searchBarTextField.setClearButtonColorTo(color: yourColor)
searchBarTextField.setPlaceholderTextColorTo(color: yourColor)
For just changing the color of the search icon, without altering the actual icon in Swift 3:
if let textField = self.searchBar.value(forKey: "searchField") as? UITextField,
let iconView = textField.leftView as? UIImageView {
iconView.image = iconView.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
iconView.tintColor = UIColor.red
}
Creates a result like so:
As per Federica's anwser....To do this in swift
var image: UIImage = UIImage(named: "search")!
self.searchBar.setImage(image, forSearchBarIcon: UISearchBarIcon.Search, state: UIControlState.Normal)
A solution for those using interface builder. You can add a User Defined Runtime Attribute to the UISearchBar:
searchField.leftView.tintColor of type Color
You can select the desired color of the icon, can be selected from your Color Assets library to support different colors for both light and dark mode.
Since iOS 13, we now have access to many standard system icons via SF Symbols. Also, if you want to have a unified colour scheme for your search bars so that they all look the same without having to duplicate code, you can use the Appearance workflow to change them all at once. For example:
let image = UIImage(systemName: "magnifyingglass")?.withTintColor(.white, renderingMode: .alwaysOriginal)
UISearchBar.appearance().setImage(image, for: .search, state: .normal)
This code sets all search bars in the app to use the standard magnifying glass icon, in white. You can use similar code to change the 'clear' button icon, the bookmark icon and the results list icon. You just need to change .search to the appropriate enumeration value and find the system name of the appropriate icon (which you can get from the free SF System app).
Another method that uses Appearance would be to set the tint colour of all views contained within a search view, though this may have unwanted effects in some cases (i.e. changing the colour of the text cursor):
UIView.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = .yellow
This will make the left icon and the text cursor yellow, though annoyingly not the 'clear' button for some reason. I prefer not to use this method as it may not be future-proof; Apple has a habit of changing things internally that can cause unexpected changes if you don't use their approved methods.
Following on from some of the answers here
If you would like to see and make the changes in storyboard first subclass UISearch bar and do as above.
However add the changes in a #IBInspectable variable and not forgetting the #IBDesignable at the top of the class and setting the searchbar subclass in the "Identity inspector"
I have added the full working subclass and code below for swift 3.0
Here you will be able to change the placeholder text, search text and magnifying glass
import UIKit
#IBDesignable
class CustomSearchBar: UISearchBar {
#IBInspectable var placeholderColor: UIColor? {
didSet {
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
let textFieldInsideSearchBarLabel = textFieldInsideSearchBar!.value(forKey: "placeholderLabel") as? UILabel
textFieldInsideSearchBarLabel?.textColor = placeholderColor
}
}
#IBInspectable var textColor: UIColor? {
didSet {
let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.textColor = textColor
}
}
#IBInspectable var magnifyingGlassColor: UIColor? {
didSet {
if let textFieldInsideSearchBar = self.value(forKey: "searchField") as? UITextField,
let glassIconView = textFieldInsideSearchBar.leftView as? UIImageView {
//Magnifying glass
glassIconView.image = glassIconView.image?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
glassIconView.tintColor = magnifyingGlassColor
} }
}
}
Make sure that when you use the setImage API, pass an image with rendering mode of UIImageRenderingModeAlwaysTemplate. For example:
[self.searchBar setImage:[[UIImage imageNamed: #"icon-search"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forSearchBarIcon:UISearchBarIconSearch state:UIControlStateNormal];
There are no adequate reasons to set your own custom image just for changing icon tint color. Don't forget about perfomance. And retrieving a value by a raw string key doesn't garantee that other coders can mistype usually calling app crashes. We're not perfect.
How about UISearchBar instance's property searchTextField (UISearchTextField)?
if let thatMysteriousLoop = yourSearchBar.searchTextField.leftView as? UIImageView {
thatMysteriousLoop.tintColor = anyColorYouWannaSet // <-- Voilà!
}
For swift 3
searchBar.setImage(UIImage(named: "location-icon-black"), for: .search, state: .normal)
My solution:
searchBar = UISearchBar()
searchBar.searchBarStyle = .minimal
searchBar.setTextColor(.white)
let textField = self.searchBar.getTextField()
let glassIconView = textField?.leftView as? UIImageView
glassIconView?.image = glassIconView?.image?.withRenderingMode(.alwaysTemplate)
glassIconView?.tintColor = .white
searchBar.showsCancelButton = true
extension UISearchBar {
func getTextField() -> UITextField? {
return self.value(forKey: "searchField") as? UITextField
}
func setTextColor(_ color: UIColor) {
let textField = getTextField()
textField?.textColor = color
}
}
I know it is an old post but since there is a Xamarin Bug on the dark mode and I was struggling for hours, I thought I share my pretty easy solution.
iOS- custom Renderer.
[assembly:ExportRenderer(typeof(SearchBar),typeof(YourProjectSearchbarRenderer))]
public class YourProjectSearchbarRenderer : SearchBarRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
// iOS >13 -> Xamarin bug on darkmode,
// just shows the light icon...
this.Control.SetImageforSearchBarIcon(UIImage.FromFile("AddAnSearchIcon.ico"), UISearchBarIcon.Search, UIControlState.Normal);
}
}
}
if(IOS_7) {
self.searchBar.searchBarStyle = UISearchBarStyleMinimal;
self.searchBar.backgroundImage = [UIImage imageWithColor:[UIColor redColor] cornerRadius:5.0f];
}

Resources