Gaurang
Gaurang

Reputation: 747

UISearchBar text color change in iOS 7

How to change text color of UISearchBar in iOS 7?

In iOS 6, I was subclassing the UISearchBar and in layoutSubviews customising the properties of UITextField subview of UISearchBar.

But in iOS 7, UISearchBar doesn't have UITextField as its subview. How to fix this?

Upvotes: 49

Views: 48973

Answers (16)

Ben
Ben

Reputation: 984

Update in Swift 3

UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).textColor = UIColor.black

Upvotes: 1

Toseef Khilji
Toseef Khilji

Reputation: 17409

In iOS 7 to access Text Field you have to reiterate on level more. Change your code like this

for (UIView *subView in self.searchBar.subviews)
{
    for (UIView *secondLevelSubview in subView.subviews){
        if ([secondLevelSubview isKindOfClass:[UITextField class]])
        {
            UITextField *searchBarTextField = (UITextField *)secondLevelSubview;

            //set font color here
            searchBarTextField.textColor = [UIColor blackColor];

            break;
        }
    }
}

Note : This is Not Public API

OR

You can use appearance Property of UIControls, Like

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];

Note: Appearance proxy can be used for iOS 9.0+ OutPut

enter image description here

You can set The tintcolor to apply to key elements in the search bar.

Use tintColor to tint foreground elements.

Use barTintColor to tint the bar background.

In iOS v7.0, all subclasses of UIView derive their behavior for tintColor from the base class. See the discussion of tintColor at the UIView level for more information. Apple Doc

Upvotes: 99

Michael
Michael

Reputation: 9864

This class will give you full control over every item in the UISearchBar


import UIKit

class SMTSearchBar: UISearchBar {

    override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        initialize()
    }

    convenience init() {
        self.init(frame: CGRectZero)
        initialize()
    }

    // Style the view
    func initialize() {

        // Search Area
        let searchField = valueForKey("searchField") as! UITextField
        searchField.textColor = Colors.White
        searchField.font = UIFont(name: Fonts.MuseoSans500, size: 16)
        searchField.backgroundColor = Colors.Black.colorWithAlphaComponent(0.1)

        // Icons
        let searchIcon = UIImage(named: Icons.Search)?.imageWithTint(Colors.White)
        let smallClearIconNormal = UIImage(named: Icons.SmallClear)?.imageWithTint(Colors.White)
        let smallClearIconHighLight = UIImage(named: Icons.SmallClear)?.imageWithTint(Colors.White.colorWithAlphaComponent(0.5))
        setImage(searchIcon, forSearchBarIcon: .Search, state: .Normal)
        setImage(smallClearIconHighLight, forSearchBarIcon: .Clear, state: .Highlighted)
        setImage(smallClearIconNormal, forSearchBarIcon: .Clear, state: .Normal)
    }

    func setPlaceHolder(placeholder: String) {
        for subView in subviews{
            for subsubView in subView.subviews {
                if let textField = subsubView as? UITextField {
                    textField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSForegroundColorAttributeName: Colors.White.colorWithAlphaComponent(0.5)])
                }
            }
        }
    }
}

Usage (in navigation bar)

let searchBar:SMTSearchBar = SMTSearchBar()
searchBar.sizeToFit()
searchBar.setPlaceHolder("Search for cool things")
navigationItem.titleView = searchBar
searchBar.becomeFirstResponder()

Upvotes: 0

Matthieu Riegler
Matthieu Riegler

Reputation: 54888

Caution : This should lead to App Rejection!

KVC FTW. This did it for me.

UITextField *searchField = [self.searchBar valueForKey:@"_searchField"];
searchField.textColor = [UIColor redColor];

Upvotes: 5

Adam Waite
Adam Waite

Reputation: 18855

Swift Extension

public extension UISearchBar {

    public func setTextColor(color: UIColor) {
        let svs = subviews.flatMap { $0.subviews }
        guard let tf = (svs.filter { $0 is UITextField }).first as? UITextField else { return }
        tf.textColor = color
    }
}

Upvotes: 4

Fernando Mata
Fernando Mata

Reputation: 492

This seems to be the correct answer https://stackoverflow.com/a/19315895/2493073

The Swift version of it is:

UITextField.appearanceWhenContainedInInstancesOfClasses([UISearchBar.self]).textColor = UIColor.blueColor()

This would only work for iOS 9.0, in order to make it work for lower versions you'll need to follow this question. https://stackoverflow.com/a/27807417/2493073

Upvotes: 4

Shanmugasundharam
Shanmugasundharam

Reputation: 2092

you can use search bar inside textfield

 UISearchBar *  searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 50, 320, 44) ];
searchBar.autocorrectionType = UITextAutocapitalizationTypeWords;
searchBar.delegate = self;
searchBar.searchBarStyle = UISearchBarStyleMinimal;
searchBar.barTintColor = [UIColor redColor];
[[UITextField appearanceWhenContainedIn:[searchBar class], nil]setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];
[self.view addSubview:searchBar];

Upvotes: 1

AechoLiu
AechoLiu

Reputation: 18368

In my case, I have multiple UISearchBar objects and they need to change the textField font color. The appearanceWhenContainedIn update one UISearchBar behavior, but another doesn't.

I subclass the UISearchBar and implement custom -(id)initWithFrame: as following, and it works.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.searchBarStyle       = UISearchBarStyleMinimal;
        self.tintColor            = [UIColor whiteColor];
        self.barTintColor         = [UIColor whiteColor];

        [[UITextField appearanceForTraitCollection:self.traitCollection whenContainedIn:[self class], nil] setDefaultTextAttributes:
         @{
           NSForegroundColorAttributeName : [UIColor whiteColor]
           }];
    }
    return self;
}

UIAppearance Protocol Reference said that,

In other words, the containment statement in appearanceWhenContainedIn: is treated as a partial ordering. Given a concrete ordering (actual subview hierarchy), UIKit selects the partial ordering that is the first unique match when reading the actual hierarchy from the window down.

So, appearanceWhenContainedIn: won't deal with all UISearchBar in the hierachy of UIWindow. And it suggests that.

Use the appearanceForTraitCollection: and appearanceForTraitCollection:whenContainedIn: methods to retrieve the proxy for a class with the specified trait collection.

Upvotes: 2

Marius
Marius

Reputation: 309

This is the right solution for iOS8:

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{NSFontAttributeName: [UIFont fontWithName:@"Helvetica" size:14], NSForegroundColorAttributeName:[UIColor lightGrayColor]}];

You have to set the font as well, otherwise, the font size will be wrong.

Upvotes: 0

Jack Solomon
Jack Solomon

Reputation: 890

The easiest way to do it is by putting this code in viewDidAppear or viewWillAppear:

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];

This works in iOS 8 and Xcode 6, unlike some of the other code. It can mess around with the font and text size, etc, but you can change that in the text attributes.

That changes the text colour for all search bars in your app. If you only want to change one, use the above code, and then in any other views with a search bar, use the same code but set the colour to whatever you want.

Upvotes: 1

Graham Dawson
Graham Dawson

Reputation: 539

For XCode 6 (iOS8 SDK) the following DOESN'T work

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor redColor]];

But the following DOES work (for deployment to iOS7 and iOS8)

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor redColor]}];

Upvotes: 35

mmackh
mmackh

Reputation: 3630

Even though I would have preferred to use appearance API, it didn't work with iOS8. Here's the least hackish solution I did come with:

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    if (self.shouldEnableSearchBar)
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^
        {
            UITextField *searchBarTextField = [[AFPBaseViewController findSubviewsOfView:self.searchBar ofClass:[UITextField class]] firstObject];
            searchBarTextField.textColor = AFPConstantsColorGold;
        });
    }

}

You could maybe even create a UIView category with this. The reason why this has to be called in viewDidAppear is that UISearchBar is actually contained in a ViewController, and doesn't load all its subviews until it has appeared on screen. It could be added into viewWillAppear too, but I haven't tested it.

+ (NSArray *)findSubviewsOfView:(UIView *)view ofClass:(Class)class
{
    NSMutableArray *targetSubviews = [NSMutableArray new];
    for (id subview in view.subviews)
    {
        if ([subview isKindOfClass:class])
        {
            [targetSubviews addObject:subview];
        }

        if ([subview subviews].count)
        {
            [targetSubviews addObjectsFromArray:[self findSubviewsOfView:subview ofClass:class]];
        }
    }
    return targetSubviews.copy;
}

Upvotes: 0

Robert Lawson
Robert Lawson

Reputation: 83

Here is working example done in C# using Xamarin:

SearchBar = new UISearchBar ();
foreach (var subView in SearchBar.Subviews) {
    foreach (var field in subView.Subviews) {
        if (field is UITextField) {
            UITextField textField = (UITextField)field;
            textField.TextColor = UIColor.White;
        }
    }
}

Hope this helps someone.

Upvotes: 4

mOp
mOp

Reputation: 385

You can set the text attributes like so

[[UITextField appearanceWhenContainedIn:[<YOUR_CONTROLLER_NAME> class], nil] setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor], NSFontAttributeName:[UIFont systemFontOfSize:14.0]}];

Upvotes: 4

Jordan Snyder
Jordan Snyder

Reputation: 123

While it's true that the UIAppearance protocol is a "public API," it's not true that UITextField supports this.

If you take a look at UITextField.h and look for the string "UI_APPEARANCE_SELECTOR" you'll see that it has no instances of this string. If you look at UIButton, you find quite a few - these are all of the properties that are officially supported by the UIAppearance API. It's somewhat well-known that UITextField is not supported by the UIAppearance API, so the code in Sandeep's answer will not always work and it's actually not the best approach.

This is a useful post with useful links: http://forums.xamarin.com/discussion/175/uitextfield-appearance

The correct approach is unfortunately messy - iterate through the subviews (or subviews of main subview for iOS7) and set it manually. Otherwise you will have unreliable results. But you can just create a category for UISearchBar and add a setTextColor:(UIColor*)color method. Example:

- (void)setTextColor:(UIColor*)color
{
    for (UIView *v in self.subviews)
    {
        if([Environment isVersion7OrHigher]) //checks UIDevice#systemVersion               
        {
            for(id subview in v.subviews)
            {
                if ([subview isKindOfClass:[UITextField class]])
                {
                    ((UITextField *)subview).textColor = color;
                }
            }
        }

        else
        {
            if ([v isKindOfClass:[UITextField class]])
            {
                ((UITextField *)v).textColor = color;
            }
        }
    }
}

Upvotes: 5

SandeepM
SandeepM

Reputation: 2609

You can set the text colour by

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor blueColor]];

Upvotes: 95

Related Questions