13

I have a UISearchBar contained within a UIView and the UIView has been assigned to a UITableView's tableHeaderView. I'm trying to style the UISearchBar to look like this:

What I want

Out of the gate, this is what it looks like:

How it looks now

There are loads of SO questions and answers on how to style UISearchBar, its search field, etc., some with particular attention to backgrounds. Many of them involve traversing the UISearchBar's subviews, finding a UISearchBarBackground (or _UISearchBarSearchFieldBackgroundView) object, and setting its background color directly. I'm trying to find a supported API for doing this, however...

The setSearchFieldBackgroundImage:forState: method seems to have great potential, but this is what I get when I use a 1px white (or transparent) image using UIControlStateNormal:

Using a transparent image for setSearchFieldBackgroundImage:forState:

Any ideas as to how to get this to work? I'd appreciate someone pointing me to a SO post that answers this, but I really do think I've read them all. Thanks a ton.

Hussain Shabbir
  • 14,801
  • 5
  • 40
  • 56
Dave
  • 183
  • 1
  • 2
  • 7

10 Answers10

7

you can use the appearanceWhenContainedIn to target elements without traversing the view hierarchy. Something like:

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setBackgroundColor:[UIColor whiteColor]];
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setTextColor:[UIColor lightGrayColor]];

UPDATE:

As appearanceWhenContainedIn is now deprecated, use

[[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar self]]] <your setter here>];
Will Von Ullrich
  • 2,129
  • 2
  • 15
  • 42
joneswah
  • 2,788
  • 3
  • 33
  • 32
4

I think the problem here is that when you use setSearchFieldBackgroundImage:forState:, the height of your image actually determines the height of the search field. The standard search field (at least as of iOS 8) is 28 points tall, so an image that height should give the effect you're after.

(Somewhat confusingly, this also means that a nine-part stretchable image generally won't look right—so if you were going for a look that wasn't just white on white, you need to use a three-part stretchable image that only stretches horizontally.)

robotspacer
  • 2,732
  • 2
  • 28
  • 50
  • That's it, use the `setSearchFieldBackgroundImage:forState:` method and in your `imageWithColor` method create a CGRect with 28px width and height – fruechtemuesli Jul 21 '15 at 09:07
3

Please try following code

[[UISearchBar appearance]setBackgroundImage:[UIImage imageNamed:@“searchbar_bg.png"]];
for (UIView *searchbuttons in searchBar.subviews) {

    if ([searchbuttons isKindOfClass:[UIButton class]]) {

        UIButton *cancelbutton = (UIButton *)searchbuttons;
        [cancelbutton setBackgroundImage:[UIImage imageNamed:@“canelBtn.png"] forState:UIControlStateNormal];
    }
}


 UITextField *searchField = [searchBar valueForKey:@"_searchField"];
 searchField.background = [UIImage imageNamed:@"bg.png"];
IKKA
  • 6,297
  • 7
  • 50
  • 88
  • This isn't quite it either. Unfortunately, `setBackgroundImage:` isn't quite right -- I'm not trying to set the background image of the search bar, I'm trying to set the background of the _search field_. – Dave Nov 19 '13 at 05:48
3

Above iOS 5.0

[[UISearchBar appearance] setSearchFieldBackgroundImage:[UIImage imageNamed:@"YourBackground.png"]forState:UIControlStateNormal];
Baby Groot
  • 4,637
  • 39
  • 52
  • 71
Dipak Narigara
  • 1,796
  • 16
  • 18
  • The third image in my question shows the result of using `setSearchFieldBackgroundImage:forState:` with a transparent or white background image. – Dave Nov 18 '13 at 14:24
3

You can use either the barTintColor or the backgroundImage property of the UISearchBar to directly accomplish what you are trying to do.

I reproduced your problem, and it seems to be solved by:

self.searchDisplayController.searchBar.barTintColor = [UIColor whiteColor];

or

self.searchDisplayController.searchBar.backgroundImage = [self imageWithColor:[UIColor whiteColor]];

P.S. If you are using the backgroundImage solution, you'll need to make the method imageWithColor as follows

- (UIImage *)imageWithColor:(UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return image;
}

Tell me if it works!

aksh1t
  • 5,410
  • 1
  • 37
  • 55
  • I was able to make this work if the `imageWithColor` method is modified to set a more appropriate height (the width will be scaled, but the height is not... at least in iOS 7.1). Try this instead: `CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 30.0f);` – Christopher Hujanen Aug 20 '14 at 14:42
  • I changed this line to have the height defined to 28.0f: ``CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 28.0f);`` It is based on response of @robotspacer – Navid Rezaei Oct 21 '14 at 18:40
2

iO9 Perfect works.

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[self searchSubviewsForTextFieldIn:self.searchBar] setBackgroundColor:  [UIColor redColor]];
}

- (UITextField*)searchSubviewsForTextFieldIn:(UIView*)view
{
    if ([view isKindOfClass:[UITextField class]]) {
        return (UITextField*)view;
    }
    UITextField *searchedTextField;
    for (UIView *subview in view.subviews) {
        searchedTextField = [self searchSubviewsForTextFieldIn:subview];
        if (searchedTextField) {
            break;
        }
    }
    return searchedTextField;
}
Arpan Dixit
  • 995
  • 1
  • 12
  • 24
1

@joneswah's answer is depricated in iOS 9.

For iOS 9 put this in your AppDelegate.m. I also added workaround for keyboard opening lag, when keyboard is initiated for the first time.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

// Remove lag on oppening the keyboard for the first time when clicked on any UITextField
UITextField *lagFreeField = [[UITextField alloc] init];
[self.window addSubview:lagFreeField];
[lagFreeField becomeFirstResponder];
[lagFreeField resignFirstResponder];
[lagFreeField removeFromSuperview];

//searchBar background color change
[[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setBackgroundColor:[UIColor greenColor]];//background color
[[UITextField appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTextColor:[UIColor blackColor];//text color

return YES;
}
Undo
  • 25,519
  • 37
  • 106
  • 129
Boris Nikolic
  • 746
  • 14
  • 24
0

As others suggested, you need to traverse through your searchbar's subviews and finding the UITextField instance. BUT, you need to set its layer.backgroundColor, as setting the backgroundColor property has no effect. I'll give an example:

for view in searchBar.subviews {
    for subview in view.subviews {
        if let searchField = subview as? UITextField {
            searchField.layer.backgroundColor = UIColor.whiteColor().CGColor
        }
    }
}

This will give you what you need.

Ivan
  • 497
  • 4
  • 11
0

My answer stably works on ios 5 and above, including this 10. Without hacks and KVO, by Apple Way

Community
  • 1
  • 1
EvGeniy Ilyin
  • 1,817
  • 1
  • 21
  • 38
-1

The following code will achieve the result.

_sbAddress.barTintColor = [UIColor whiteColor];

    for (UIView *subView in _sbAddress.subviews) {
        for(id field in subView.subviews){
            if ([field isKindOfClass:[UITextField class]]) {
                UITextField *textField = (UITextField *)field;
                [textField setPlaceholder:@"Search"];
            }
        }
    }

OR

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setPlaceholder:@"Search"];
Azhar
  • 20,500
  • 38
  • 146
  • 211