UISearchBar transparent background view
Asked Answered
H

12

21

In UISearchBar default a background view should present. How to hide that? I need only the search textview part, in UISearchBar.

Huertas answered 26/5, 2010 at 13:42 Comment(0)
M
61
[[searchBar.subviews objectAtIndex:0] removeFromSuperview];
Mandrel answered 6/7, 2010 at 13:28 Comment(7)
This worked for me when used with the following line: searchBar.backgroundColor = [UIColor clearColor];Endometrium
I'm using Xcode 4.01 and iOS 4.3. This doesn't work for me. Also tried using clearColor as suggested above, with no progress.Regiment
I verified that there's no change between 4.2 and 4.3 - if nothing else is disappearing, you might not have the IB connections set up right.Mandrel
This seems to work, but has the odd prerequisite that the searchbar style is set to black translucentSacerdotal
I only needed to set it to translucent - I didn't need to change it to black as well.Wealth
Haha I think it's even funny as a solution i like it!Sot
It worked for me (iOS 6.1 simulator, Xcode 5.0.2), without any hacks, BUT BE CAREFUL! In iOS 7 it removes the searchBar itself, so you should check the iOS version before using this hack.Indelible
P
24

Here there is a solution working for iOS 5 and iOS 6. I have checked that it is not necessary to change any other property (like setting the backgroundColor to [UIColor clearColor]) to make it work.

for (UIView * v in searchBar.subviews) {
    if ([v isKindOfClass:NSClassFromString(@"UISearchBarTextField")]) {
        v.superview.alpha = 0;
        UIView *containerView = [[UIView alloc] initWithFrame:searchBar.frame];
        [containerView addSubview:v];
        [self.view addSubview:containerView];
    }
}
Prisilla answered 1/10, 2012 at 15:34 Comment(2)
+1 tried like 5 other ones (setting image and so on..) that did not work, but this one worked right away in ios 6!Pase
There is a much less hackie solution, check @Coeur's answerRink
E
18

Starting iOS 5, I would recommend the following way of doing, which avoids messing up with the undocumented subviews. Replace self with self.searchBar if you're subclassing the UISearchBarController instead of the UISearchBar itself.

// transparency for UISearchBar
self.translucent = YES;
self.backgroundImage = [UIImage new];
self.scopeBarBackgroundImage = [UIImage new];

And as a bonus:

// transparency for UIToolbar
self.translucent = YES;
[self setBackgroundImage:[UIImage new] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];
[self setShadowImage:[UIImage new] forToolbarPosition:UIToolbarPositionAny];

// transparency for UINavigationBar
self.translucent = YES;
[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
self.shadowImage = [UIImage new];

// transparency for UITabBar
self.backgroundImage = [UIImage new];
self.shadowImage = [UIImage new];
Extinguish answered 13/8, 2013 at 9:27 Comment(1)
Amazing answer. Thanks so much for updating this old post. Luckily I saved the link in my code and came to it because I'm fighting iOS7 compatibility.Anglicanism
F
11

Update: as of iOS 5.0, if you have a background image available, you can now do

searchBar.backgroundImage = someUIImage;

(only tested on iOS 6, so may be bugged on 5 though! Will check around.)

Brandon's answer no longer works (or doesn't for me, anyway), so I looked around a bit and noted:

(gdb) po [searchBar subviews]
<__NSArrayM 0x665ab80>(
<UISegmentedControl: 0x63aad80; frame = (0 0; 225 44); opaque = NO; layer = <CALayer: 0x6368420>>,
<UISearchBarBackground: 0x6347280; frame = (0 0; 225 44); layer = <CALayer: 0x638a230>>,
<UISearchBarTextField: 0x6331110; frame = (0 0; 0 0); clipsToBounds = YES; opaque = NO; layer = <CALayer: 0x63a20f0>>
)

The 3rd entry is a custom text field and presumably it is the one I want, I thought, but removing subview 0 AND 1 from superview didn't fix it oddly enough. I ended up with the following, which does work:

UITextField *sbTextField = (UITextField *)[searchBar.subviews lastObject];
[sbTextField removeFromSuperview];
[self.view addSubview:sbTextField];
sbTextField.frame = searchBar.frame;
[searchBar removeFromSuperview];

To make that a bit more robust, it's probably a good idea to check that the class is a subclass of text field and such, but unless it breaks I'm just leaving it simple.

Edit: switched objectAtIndex:2 to lastObject as tipycalFlow suggested.

Flameproof answered 5/5, 2011 at 14:39 Comment(4)
+1, Great hack! It is odd but removing subview at index:2 should not work all the time because the array size is apparently not fixed. A better way would be UITextField *sbTextField = (UITextField *)[searchBar.subviews lastObject];Retha
Daniel: have one app in the app store using this as we speak.Flameproof
There is a much less hackie solution, check @Coeur's answerRink
Setting backgroundImage isn't hacky, and @Coeur's answer doesn't work for me under iOS 7 anyway. The bar tint is always washed out even when translucent is set to NO.Claresta
F
10

For future visitors looking for an answer. I have found the following to be effective in iOS 5+ and prefer it as it doesn't involve messing with the layout of the UISearchBar itself.

UISearchBar * search = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44)];
[search setBackgroundColor:[UIColor clearColor]];
[search setPlaceholder:@"Search"];

for (UIView * v in [search subviews]) {
    if (![v isKindOfClass:[UITextField class]]) {
        v.alpha = 0;
    }
}

[header addSubview:search];
[search release];
Friesian answered 31/7, 2012 at 10:45 Comment(0)
L
2

The UISearchBar background cannot be hidden by public methods (assigning a transparent color as the tintColor won't help).

You should use a UITextField if you want precise control on the text field's style.

Lindalindahl answered 26/5, 2010 at 14:54 Comment(1)
That's really important if you still support iOS 4.x.Scissel
G
2

I experimented with using a mask layer in order to make everything around the actual text field in the search bar transparent (thus showing the content from the view underneath). It works, but i'd be nervous to use it in a shipping app since you have to match the shape of your mask exactly to the shape of the text field in UISearchBar. If Apple changes the shape of the text field at all, then your mask won't fit and you'll see parts of the search bar gradient that you don't want and/or you won't see parts of the text field that you do want. That said, here's how i did it:

//first make sure you include core animation so that the compiler will know about your view's layer
#import <QuartzCore/QuartzCore.h>

//now make a mask.  this is basically just a solid colored shape.  When you apply the mask, anywhere where the color is solid will become transparent in your view.  i used the excellent Opacity (http://likethought.com/opacity/) to generate this code, but you can do it any way you'd like

@interface SearchMaskLayer : CALayer {
}
@end

@implementation SearchMaskLayer

- (void)drawInContext:(CGContextRef)context
{


    CGRect imageBounds = CGRectMake(0, 0, 310, 34);
    CGRect bounds = imageBounds;

    CGFloat alignStroke;
    CGFloat resolution;
    CGMutablePathRef path;
    CGPoint point;
    CGPoint controlPoint1;
    CGPoint controlPoint2;
    UIColor *color;
    resolution = 0.5 * (bounds.size.width / imageBounds.size.width + bounds.size.height / imageBounds.size.height);

    CGContextSaveGState(context);
    CGContextTranslateCTM(context, bounds.origin.x, bounds.origin.y);
    CGContextScaleCTM(context, (bounds.size.width / imageBounds.size.width), (bounds.size.height / imageBounds.size.height));

    // Layer 1

    alignStroke = 0.0;
    path = CGPathCreateMutable();
    point = CGPointMake(295.0, 32.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    CGPathMoveToPoint(path, NULL, point.x, point.y);
    point = CGPointMake(310.0, 17.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    controlPoint1 = CGPointMake(303.229, 32.0);
    controlPoint1.x = (round(resolution * controlPoint1.x + alignStroke) - alignStroke) / resolution;
    controlPoint1.y = (round(resolution * controlPoint1.y + alignStroke) - alignStroke) / resolution;
    controlPoint2 = CGPointMake(310.0, 25.229);
    controlPoint2.x = (round(resolution * controlPoint2.x + alignStroke) - alignStroke) / resolution;
    controlPoint2.y = (round(resolution * controlPoint2.y + alignStroke) - alignStroke) / resolution;
    CGPathAddCurveToPoint(path, NULL, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, point.x, point.y);
    point = CGPointMake(310.0, 17.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    CGPathAddLineToPoint(path, NULL, point.x, point.y);
    point = CGPointMake(295.0, 2.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    controlPoint1 = CGPointMake(310.0, 8.771);
    controlPoint1.x = (round(resolution * controlPoint1.x + alignStroke) - alignStroke) / resolution;
    controlPoint1.y = (round(resolution * controlPoint1.y + alignStroke) - alignStroke) / resolution;
    controlPoint2 = CGPointMake(303.229, 2.0);
    controlPoint2.x = (round(resolution * controlPoint2.x + alignStroke) - alignStroke) / resolution;
    controlPoint2.y = (round(resolution * controlPoint2.y + alignStroke) - alignStroke) / resolution;
    CGPathAddCurveToPoint(path, NULL, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, point.x, point.y);
    point = CGPointMake(15.0, 2.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    CGPathAddLineToPoint(path, NULL, point.x, point.y);
    point = CGPointMake(0.0, 17.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    controlPoint1 = CGPointMake(6.771, 2.0);
    controlPoint1.x = (round(resolution * controlPoint1.x + alignStroke) - alignStroke) / resolution;
    controlPoint1.y = (round(resolution * controlPoint1.y + alignStroke) - alignStroke) / resolution;
    controlPoint2 = CGPointMake(0.0, 8.771);
    controlPoint2.x = (round(resolution * controlPoint2.x + alignStroke) - alignStroke) / resolution;
    controlPoint2.y = (round(resolution * controlPoint2.y + alignStroke) - alignStroke) / resolution;
    CGPathAddCurveToPoint(path, NULL, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, point.x, point.y);
    point = CGPointMake(0.0, 17.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    CGPathAddLineToPoint(path, NULL, point.x, point.y);
    point = CGPointMake(15.0, 32.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    controlPoint1 = CGPointMake(0.0, 25.229);
    controlPoint1.x = (round(resolution * controlPoint1.x + alignStroke) - alignStroke) / resolution;
    controlPoint1.y = (round(resolution * controlPoint1.y + alignStroke) - alignStroke) / resolution;
    controlPoint2 = CGPointMake(6.771, 32.0);
    controlPoint2.x = (round(resolution * controlPoint2.x + alignStroke) - alignStroke) / resolution;
    controlPoint2.y = (round(resolution * controlPoint2.y + alignStroke) - alignStroke) / resolution;
    CGPathAddCurveToPoint(path, NULL, controlPoint1.x, controlPoint1.y, controlPoint2.x, controlPoint2.y, point.x, point.y);
    point = CGPointMake(295.0, 32.0);
    point.x = (round(resolution * point.x + alignStroke) - alignStroke) / resolution;
    point.y = (round(resolution * point.y + alignStroke) - alignStroke) / resolution;
    CGPathAddLineToPoint(path, NULL, point.x, point.y);
    CGPathCloseSubpath(path);
    color = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    [color setFill];
    CGContextAddPath(context, path);
    CGContextFillPath(context);
    CGPathRelease(path);
}

Later in one of your methods, apply the mask

- (void)viewDidLoad {
    [super viewDidLoad];
    SearchMaskLayer *maskLayer = [[SearchMaskLayer alloc] init];
    [maskLayer setFrame:CGRectMake(0, 0, 310, 34)];
    [maskLayer setPosition:CGPointMake(162,21)];
    [maskLayer setNeedsDisplay];    
    [self.searchBar.layer setNeedsDisplay];
    [self.searchBar.layer setMask:maskLayer];
    [maskLayer release];
}

I fudged the positioning of the layer just to see what it would look like, but you could calculate those sizes and positions to suit your needs.

Gotha answered 4/6, 2010 at 16:26 Comment(4)
if running into compile errors, make sure quartzcore framework is included: #2968571Langouste
holy god, this works! its abit rough on the edges, so kalperin, if you have an updated version, please share : ) in the meantime i will try to see if i can poke around to make this fit my needs.Langouste
unfortunately, somehow attaching this masks prevents the uisearchbar to autoresize when the view size changes, say portrait to landscape. not viable for me, but very very cool!Langouste
@Ying, i don't have an update. I still wouldn't want to ship anything like this (irrespective of your autoresizing trouble) but layer masking is a useful tool nonetheless.Gotha
B
2

Here is my blog post concerning this issue.

I followed a similar approach to Weaverfish. However, I encapsulated the process of setting the subviews alpha property in a class of its own.

You can subclass UISearchBar as follow:

in UITransparentBackgroundSearchBar.h:

#import <UIKit/UIKit.h>
@interface UITransparentBackgroundSearchBar : UISearchBar
@end

and in UITransparentBackgroundSearchBar.m:

#import "UITransparentBackgroundSearchBar.h"
@implementation UITransparentBackgroundSearchBar

-(void)didAddSubview:(UIView *)subview {
    if (![subview isKindOfClass:[UITextField class]]) {
        subview.alpha = 0;
    }
}

@end

In your storyboard, set the search bar class to be UITransparentBackgroundSearchBar and voilà.

Now, I am new to iOS development so I can't say this is bulletproof. It seems to work and it avoids code duplication if I need the same transparent background in another view.

Bayberry answered 5/9, 2012 at 19:53 Comment(0)
R
1

None of the answers worked for me except that of Kalle's. but with minor refinements.

UITextField *sbTextField = (UITextField *)[self.mSearchBar.subviews lastObject];
[sbTextField removeFromSuperview];
[self.view addSubview:sbTextField];
CGRect sbFrame = self.mSearchBar.frame;
// Set the default height of a textfield
sbFrame.size.height = 31;   

/* 8 is the top padding for textfield inside searchbar
 * You may need to add a variable to 8 according to your requirement.
 */
sbFrame.origin.y = 8+ self.mSearchBar.superview.frame.origin.y;
sbTextField.frame = sbFrame;

[sbTextField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin];  //to support different orientations.
[self.mSearchBar removeFromSuperview];

+1 to Kalle. (thumbs up)

Romance answered 18/5, 2012 at 5:58 Comment(0)
J
1

It is easily made by setting transparent image of 1px * 1px for backgroundImage property. Tested on ios 5, 6.

searchBar.backgroundImage = [UIImage imageNamed:@"transparentImage.png"];
Jocular answered 20/12, 2012 at 14:30 Comment(2)
This works but I've found out that you have to set searchBar.scopeBarBackgroundImage to the same transparent image as well.Hilar
I like this solution because it's not involved with any hack. This is less fragile than other hacks.Tabu
E
1

No hack here:

if (([[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] == NSOrderedAscending)) {
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 1), NO, 0.0);
    UIImage *blank = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    searchBar.backgroundImage = blank;
    searchBar.backgroundColor = [UIColor clearColor];
}
else {
    searchBar.barTintColor = [UIColor clearColor];
}
Eryneryngo answered 16/4, 2014 at 15:59 Comment(0)
B
0

Brandon's answer still works, but with the condition mentioned by Timothy Groote. It's as simple as removing the two lower subviews, and making sure the style is set to translucent black (I did it in IB, but I'm assuming doing it in code would work).

Just out of curiosity why do you guys think this won't get approved? The solution uses only public APIs.

Buffon answered 30/6, 2011 at 9:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.