开发者

UISearchBar transparent background view

开发者 https://www.devze.com 2023-01-01 16:13 出处:网络
In UISearchBar default a background view should present开发者_运维技巧. How to hide that? I need only the search textview part, in UISearchBar.[[searchBar.subviews objectAtIndex:0] removeFromSuperview

In UISearchBar default a background view should present开发者_运维技巧. How to hide that? I need only the search textview part, in UISearchBar.


[[searchBar.subviews objectAtIndex:0] removeFromSuperview];


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];
    }
}


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];


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.


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];


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.


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.


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.


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)


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"];


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];
}


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消