Custom UISearchBar wrong tint under UINavigationBar - ios

I can't get my head around this issue: I have a UISearchBar subclass that I'm using with a UISeachDisplayControlller in a UITableViewController that adds a button on the left side and makes the UISearchTextField smaller so it can fit both views.
I set the frames manually in layoutSubviews even tough I'm using AutoLayout across the project.
The code looks something like this:
UIView *searchBarView = [self.subviews objectAtIndex:0];
[searchBarView addSubview:_annotationsButton];
for (UIView *subview in searchBarView.subviews) {
if ([subview isKindOfClass:[UITextField class]]) {
// Change the border color of the UISearchTextField
[subview.layer setBorderWidth:1.0];
[subview.layer setBorderColor:[UIColor colorFromHexString:#"#77848D"].CGColor];
[subview.layer setCornerRadius:2.0];
}
}
[self setBackgroundImage:[UIImage imageWithColor:[UIColor whiteColor]]];
self.separator = [[UIView alloc] initWithFrame:CGRectMake(0, self.bounds.size.height-1, self.bounds.size.width, 1)];
[self.separator setBackgroundColor:[UIColor colorFromHexString:#"#d6d0cc"]];
[searchBarView addSubview:self.separator];
The strange result looks like this:
As you can see, the bar is grayed out.
The layoutSubviews method is the following:
- (void)layoutSubviews{
[super layoutSubviews];
UIView *searchBarView = [self.subviews objectAtIndex:0];
for (UIView *subview in searchBarView.subviews) {
if ([subview isKindOfClass:[UITextField class]]) {
CGRect textFieldFrame = [subview frame];
if (!subview.isFirstResponder) {
self.originalFrame = textFieldFrame;
CGRect newTextFieldRect = CGRectMake(self.originalFrame.origin.x + self.originalFrame.size.width /2,
self.originalFrame.origin.y,
self.originalFrame.size.width /2 - kPadding,
self.originalFrame.size.height);
[subview setFrame:newTextFieldRect];
CGRect annotationsButtonFrame = CGRectMake(kPadding,
self.originalFrame.origin.y,
self.originalFrame.size.width /2 - kPadding,
self.originalFrame.size.height);
[self.annotationsButton setFrame:annotationsButtonFrame];
[self.annotationsButton setHidden:NO];
}
else {
[self.annotationsButton setHidden:YES];
}
}
}
[self.separator setFrame:CGRectMake(0, self.bounds.size.height-1, self.bounds.size.width, 1)];
}
In this method, I just adjust the frames of the UISearchBarTextField and _annotationsButton so they do not overlap.

Whenever the background is set with an image this happens.
I managed to set the bar translucent and with this line:
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
self.searchBarStyle = UISearchBarStyleMinimal;
}
I fixed my issue.

Related

Scrollview should start from where I left it last time

I have a scrollview(timesScrollView) which is added as a subview on a view(dropDownView).The view is hidden until a particular button is pressed, when that button is pressed view will appear.
(IBAction)how_many_times_btn_click:(id)sender{
if(howMany==false){
for(UIView *view in dropDownView.subviews)
{
[view removeFromSuperview];
}
howMany=true;
duration=false;
how_many_times_btn.backgroundColor=[UIColor colorWithRed:130/255.0f green:189/255.0f blue:31/255.0f alpha:1.0f];
durationBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
startBtn.backgroundColor=[UIColor colorWithRed:62/255.0f green:67/255.0f blue:79/255.0f alpha:1.0f];
dropDownView.hidden=NO;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,70);
dropDownView.backgroundColor=[UIColor colorWithRed:37/255.0f green:42/255.0f blue:54/255.0f alpha:1.0f];
//dropDownView.backgroundColor=[UIColor whiteColor];
targetLbl=[[UILabel alloc]init];
targetLbl.frame=CGRectMake(0, 30, dropDownView.frame.size.width,30);
targetLbl.text=#"TARGET";
targetLbl.textColor=[UIColor whiteColor];
targetLbl.font=[UIFont boldSystemFontOfSize:22];
targetLbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl=[[UILabel alloc]init];
how_many_Lbl.frame=CGRectMake(0, targetLbl.frame.origin.y+targetLbl.frame.size.height, dropDownView.frame.size.width, 20);
how_many_Lbl.textAlignment=NSTextAlignmentCenter;
how_many_Lbl.text=#"HOW MANY TIMES WILL YOU DO IT?";
how_many_Lbl.textColor=[UIColor colorWithRed:65/255.0f green:71/255.0f blue:80/255.0f alpha:1.0f];
how_many_Lbl.font=[UIFont systemFontOfSize:10.0f];
hideViewBtn=[UIButton buttonWithType:UIButtonTypeCustom];
hideViewBtn.frame=CGRectMake(dropDownView.frame.size.width-30,20,20,20);
[hideViewBtn setImage:[UIImage imageNamed:#"Close Icon [ x ]"] forState:UIControlStateNormal];
[hideViewBtn addTarget:self action:#selector(hideView) forControlEvents:UIControlEventTouchUpInside];
//hideViewBtn.backgroundColor=[UIColor whiteColor];
self.timesScroll=[[LTInfiniteScrollView alloc] initWithFrame:CGRectMake(0, how_many_Lbl.frame.origin.y+how_many_Lbl.frame.size.height+16, dropDownView.frame.size.width, 102)];
//self.timesScroll.backgroundColor=[UIColor whiteColor];
self.timesScroll.verticalScroll=NO;
self.timesScroll.dataSource=self;
self.timesScroll.maxScrollDistance=5;
self.timesScroll.contentInset=UIEdgeInsetsMake(0, self.timesScroll.frame.size.width/2-31, 0,self.timesScroll.frame.size.width/2-31 );
self.timesScroll.userInteractionEnabled=YES;
self.timesScroll.exclusiveTouch=YES;
dropDownView.frame=CGRectMake(0, 0, self.view.frame.size.width,_timesScroll.frame.origin.y+_timesScroll.frame.size.height+20);
[self viewWillAppear:YES];
[dropDownView addSubview:targetLbl];
[dropDownView addSubview:how_many_Lbl];
[dropDownView addSubview:hideViewBtn];
[dropDownView addSubview:_timesScroll];
}
else
{
[self hideView];
}
}
The method above is what I am using to create view.
Now my problem is that when that particular button(how_many_times_btn) is pressed again all views are first removed then added as you can see and scrollview starts from initial position but I want it show from where I left it last time how_many_times_btn was clicked.
Hope you can understand What I am trying to say....if not I am happy to elaborate furthur.
you can get the last position by delegate methods
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
nslog(#"%f %f",scrollView.contentOffset.x,scrollView.contentOffset.y);
}
and store the x and y value and set
scrollView.contentOffset = CGPointMake(x,y);
You can save contentOffsetto one variable of CGPoint. And use this variable 's value later to scroll the UIScrollview.
Something like below line of code :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
contentOffset = scrollView.contentOffset;
}
When button pressed write below line of code:
self.timesScroll .contentOffset = contentOffset;
I'm using LTInfiniteScrollview in which there is a method 'reloadDataWithInitialIndex'
-(void)reloadDataWithInitialIndex:(NSInteger)initialIndex
{
for (UIView *view in self.scrollView.subviews) {
[view removeFromSuperview];
}
self.views = [NSMutableDictionary dictionary];
self.visibleViewCount = [self.dataSource numberOfVisibleViews];
self.totalViewCount = [self.dataSource numberOfViews];
[self updateSize];
_currentIndex = initialIndex;
self.scrollView.contentOffset = [self contentOffsetForIndex:_currentIndex];
[self reArrangeViews];
[self updateProgress];}
This method is called in 'viewWillAppear'
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.viewSize = CGRectGetWidth(self.view.frame) / Number_of_visibleViews;
self.timesScroll.delegate=self;
[self.timesScroll reloadDataWithInitialIndex:howIndex];}
I just passed previous index value here.

Change vertical position of back button text in UINavigationBar

I've been able to change the vertical posiiton of the back button icon but not the text.
I'm using the layoutSubviews method in UINavigationBar:
- (void)layoutSubviews {
[super layoutSubviews];
BOOL fixed = NO;
NSArray *classNamesToReposition = #[#"_UINavigationBarBackIndicatorView", #"UINavigationButton", #"UINavigationItemButtonView"];
for (UIView *view in [self subviews]) {
if ([classNamesToReposition containsObject:NSStringFromClass([view class])] && !fixed) {
CGRect frame = [view frame];
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
frame.origin.y = 14.5;
} else if ([NSStringFromClass([view class]) isEqualToString:#"UINavigationButton"]) {
frame.origin.y = 9.0;
} else if ([NSStringFromClass([view class]) isEqualToString:#"UINavigationItemButtonView"]) {
frame.origin.y = 5.0;
}
[view setFrame:frame];
}
}
}
The problem is that any frame change I make on UINavigationItemButtonView does not seem to have any effect, nor any frame change I make on it's UILabel subview that is the actual button text. When I log the views the frames seem to be changing but the text is not moving in my view. What am I doing wrong?
You subclass a UINavigationBar called MyNavigationBar, in layoutSubviews, change the back indicator position.
for (UIView *view in [self subviews]) {
CGRect frame = [view frame];
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
frame.origin.y = 19.5; //default is 11.5, move down by 8.
}
[view setFrame:frame];
}
And you can change backBarItem's title position by adding this in applicationDidFinished.
[[UIBarButtonItem appearanceWhenContainedIn:[MyNavigationBar class], nil] setBackButtonTitlePositionAdjustment:UIOffsetMake(0, 8) forBarMetrics:UIBarMetricsDefault];

Rectangular UISearchBar on iOS 7

I'm trying to make a UISearchBar rectangular instead of rounded, but all the solutions I found so far (mostly iterating through subviews) seem broken on iOS 7.
I did some research myself and as it turns out, it only has a UIView subview, which has additional subviews, a UISearchBarBackground and a UISearchBarTextField (both of them are private classes).
I tried
if ([view isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
[view removeFromSuperview];
}
and
if ([view conformsToProtocol:#protocol(UITextInputTraits)]) {
#try {
[(UITextField *)view setBorderStyle:UITextBorderStyleRoundedRect];
}
#catch (NSException * e) {
// ignore exception
}
}
where view is the subview of that one UIView subview but none of them seems to work.
Try this... (I know it is also using subview but it is working in ios7)
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 20, 320, 49)];
[self.view addSubview:searchBar];
[self checkSubViewsOfView:searchBar WithTabIndex:#""];
and Add this method
-(void)checkSubViewsOfView:(UIView *)view WithTabIndex:(NSString *)strTab
{
if ([view isKindOfClass:NSClassFromString(#"UISearchBarTextField")])
{
view.layer.borderWidth = 1;
view.layer.borderColor = [[UIColor whiteColor] CGColor];
return;
}
for (UIView *vvv in view.subviews)
{
NSLog(#"%#%#",strTab,[vvv description]);
if (vvv.subviews > 0)
{
NSString *str = [NSString stringWithFormat:#"____%#",strTab];
[self checkSubViewsOfView:vvv WithTabIndex:str];
}
}
}
you can set the searchfield-background like this:
[self.searchBar setSearchFieldBackgroundImage:[[UIImage imageNamed:#"searchbar_stretch-0-10-0-10"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 10, 0, 10)] forState:UIControlStateNormal];
and the searchbar-background like this:
[self.searchBar setBackgroundImage:[UIImage imageNamed:#"categories_navbar"]];

Remove gradient background from UIWebView?

How do remove the gradient from a UIWebView - the one that you see if you overscroll the top or bottom.
This code
webView.backgroundColor = [UIColor whiteColor];
just changes the color of the gradient, it doesn't removes it. How can this be done?
(note: not the same question as UIWebView underside)
Aha, yes terminology fail. I wouldn't call that a shadow at all, but c'est la vie. Here is my type-safe code to achieve the effect. To summarise: this will hide any image-view children of the scroll view. It's not as vulnerable to change as the (objectAtIndex:0) methods, so if Apple re-order the children of the webView control it will work fine, but still relies on the fact that the gradient effect is applied by imageviews parented to the scroll view (and that there is indeed a scrollview underpinning the web view).
{
webView.backgroundColor = [UIColor whiteColor];
for (UIView* subView in [webView subviews])
{
if ([subView isKindOfClass:[UIScrollView class]]) {
for (UIView* shadowView in [subView subviews])
{
if ([shadowView isKindOfClass:[UIImageView class]]) {
[shadowView setHidden:YES];
}
}
}
}
}
To transparent the UIWebView and remove the scrolls.
webView.opaque = NO;
webView.backgroundColor = [UIColor clearColor];
for(UIView *view in webView.subviews){
if ([view isKindOfClass:[UIImageView class]]) {
// to transparent
[view removeFromSuperview];
}
if ([view isKindOfClass:[UIScrollView class]]) {
UIScrollView *sView = (UIScrollView *)view;
for (UIView* shadowView in [sView subviews]){
//to remove shadow
if ([shadowView isKindOfClass:[UIImageView class]]) {
[shadowView setHidden:YES];
}
}
}
}
for hide scroll indicators
You mean the shadow? Remove UIWebView Shadow?
The only way I found how to do this was :
for(UIView *aView in [[[webView subviews] objectAtIndex:0] subviews]) {
if([aView isKindOfClass:[UIImageView class]]) { aView.hidden = YES; }
}
It just just steps thru the subviews of UIWebView and removes the view if it is an image view.
I haven't put this in any App Store apps, so I don't know if Apple would accept it.
EDIT: Brian's link provides more details.
Using method suggested above you won't be able to edit your scroll indicator/insets later. They appear as UIImageView also, so you should check for last object:
UIView* lastView = [[subView subviews] lastObject];
for (UIView* shadowView in [subView subviews])
{
if(shadowView!=lastView) ... <-this one is a scroll
}
I was able to do this by adding white subviews to the top and bottom of the WebView’s scrollView. I control the content of the WebView, so I know that white is OK - this won’t work if you are loading arbitrary content.
// _topCover and _bottomCover are ivar UIViews
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// with cover views 300pt high, I couldn't scroll far enough to see the shadow,
// even in portrait on an iPad, which gives you the longest scroll distance
CGFloat coverage = 300;
_topCover = [[UIView alloc] initWithFrame:CGRectMake(0, -coverage, webView.bounds.size.width, coverage)];
_bottomCover = [[UIView alloc] initWithFrame:CGRectMake(0, webView.scrollView.contentSize.height, webView.bounds.size.width, coverage)];
_topCover.backgroundColor = [UIColor whiteColor];
_bottomCover.backgroundColor = [UIColor whiteColor];
// in case the webView is resized, e.g. by rotating the device
_topCover.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth;
_bottomCover.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
[webView.scrollView addSubview:_topCover];
[webView.scrollView addSubview:_bottomCover];
}
I run it it after the page loads so that webView.scrollView.contentSize.height will give me the correct height. I’m not sure how this will work if your pages are dynamically changing height. My page loads only once; if yours is reloading, you will want to skip running alloc/init on _topCover and _bottomCover after the first time for efficiency.
Update: I’m not sure that my use of autoresizingMask, above, is sufficient when the view rotates. You may need to put this in the UIViewController that contains your UIWebView to resize the covers after rotating:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
CGFloat coverage = 300;
_topCover.frame = CGRectMake(0, -coverage, self.webView.bounds.size.width, coverage);
_bottomCover.frame = CGRectMake(0, self.webView.scrollView.contentSize.height, self.webView.bounds.size.width, coverage);
}
I've built upon #damithH 's answer
#implementation UIWebView (Extensions)
- (void)setBackgroundAndShadowVisible:(BOOL)visible
{
self.opaque = !visible;
self.backgroundColor = [self.backgroundColor colorWithAlphaComponent:visible ? 1.0 : 0.0];
for(UIView *view in [self subviews])
{
if([view isKindOfClass:[UIImageView class]])
{
view.hidden = !visible;
}
if([view isKindOfClass:[UIScrollView class]])
{
UIScrollView *scrollView = (UIScrollView *)view;
for (UIView *shadowView in [scrollView subviews])
{
if ([shadowView isKindOfClass:[UIImageView class]])
{
shadowView.hidden = !visible;
}
}
}
}
}
#end
if (UIDevice.currentDevice.systemVersion.intValue < 7)
for (UIImageView *imageView in webView.scrollView.subviews)
if ([imageView isKindOfClass:[UIImageView class]] && imageView.image.size.width == 1)
imageView.hidden = YES;

UISearchBar: clear background color or set background image [duplicate]

This question already has answers here:
How to change inside background color of UISearchBar component on iOS
(26 answers)
Closed 7 years ago.
How can set the background image, or clear the background, of a search bar, like the note application?
A future-proof way:
[searchBar setBackgroundImage:[UIImage new]];
[searchBar setTranslucent:YES];
mj_ has the answer that i used. i was just going to comment as such but i can't yet. So i'll just post my own answer with my implementation where I add a search bar to the top of a table view with a semi-transparent BG.
DLog(#" Add search bar to table view");
//could be a UIImageView to display an image..?
bg = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 45)] autorelease];
bg.backgroundColor = [UIColor blackColor];
UISearchBar *sb = [[[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, 290, 45)] autorelease];
sb.barStyle = UIBarStyleBlackTranslucent;
sb.showsCancelButton = NO;
sb.autocorrectionType = UITextAutocorrectionTypeNo;
sb.autocapitalizationType = UITextAutocapitalizationTypeNone;
sb.delegate = self;
[bg addSubview:sb];
table.tableHeaderView = bg;
for (UIView *subview in sb.subviews) {
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
[subview removeFromSuperview];
break;
}
}
I had problems w/ the answer above. I used the following.
for (UIView *subview in searchBar.subviews) {
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
[subview removeFromSuperview];
break;
}
}
This worked for me (ios4.2+)
// Change the search bar background
-(void)viewWillAppear:(BOOL)animated {
for (UIView *subview in self.searchBar.subviews) {
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
UIView *bg = [[UIView alloc] initWithFrame:subview.frame];
bg.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"search_bar_bg"]];
[self.searchBar insertSubview:bg aboveSubview:subview];
[subview removeFromSuperview];
break;
}
}
}
I just came up with a solution that works really well. You have to override the UISearchBar and then hide both the Background and Segment Control layers. Then Draw the background.
# .m
#import "UISearchBar.h"
#import <QuartzCore/QuartzCore.h>
#implementation UISearchBar(CustomBackground)
- (id)init
{
for ( UIView * subview in self.subviews )
{
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground") ] )
subview.alpha = 0.0;
if ([subview isKindOfClass:NSClassFromString(#"UISegmentedControl") ] )
subview.alpha = 0.0;
}
return self;
}
+ (UIImage *) bgImagePortrait
{
static UIImage *image = nil;
if (image == nil)
image = [[UIImage imageNamed:#"UISearchBarBack.png"] retain ];
return image;
}
+ (UIImage *) bgImageLandscape
{
static UIImage *image = nil;
if (image == nil)
image = [[UIImage imageNamed:#"UISearchBarBack.png"] retain];
return image;
}
- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)contenxt
{
if ([self isMemberOfClass:[UISearchBar class]] == NO)
return;
UIImage * image = ( self.frame.size.width > 320 ) ? [UISearchBar bgImageLandscape ] : [UISearchBar bgImagePortrait ];
for ( UIView * subview in self.subviews ) {
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground") ] )
subview.alpha = 0.0;
if ([subview isKindOfClass:NSClassFromString(#"UISegmentedControl") ] )
subview.alpha = 0.0;
}
CGContextTranslateCTM( contenxt , 0 , image.size.height );
CGContextScaleCTM( contenxt, 1.0, -1.0 );
CGContextDrawImage( contenxt , CGRectMake( 0 , 0 , image.size.width , image.size.height ), image.CGImage );
}
#end
# .h
#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>
#interface UISearchBar(CustomBackground)
#end
Hope this helps!
You have two questions here:
1.UISearchBar clear background color:
See my answer here
2.Set background image
Solution:(If you are in iOS 5.0 +)
[[UISearchBar appearance]setSearchFieldBackgroundImage:[navBarGradImage resizableImageWithCapInsets:inset2] forState:UIControlStateNormal];
NOTE: You can also try using a transparent image as a background.
Hope this helps.
I prefer to just set the alpha to 0 so you can hide/show on demand.
// Hide
[[self.theSearchBar.subviews objectAtIndex:0] setAlpha:0.0];
// Show
[[self.theSearchBar.subviews objectAtIndex:0] setAlpha:1.0];
How to set background color in UISearchBar:
#import <QuartzCore/QuartzCore.h>
Then make an outlet connection to search bar (say, objSearchbar), and use these lines :
for (UIView *subview in self.objSearchbar.subviews)
{
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")])
{
[subview removeFromSuperview];
break;
}
}
self.tweetSearchbar.layer.backgroundColor = [UIColor blueColor].CGColor;
searchBar.searchBarStyle = UISearchBarStyleMinimal;
Look here: UISearchbar background image change
with iOS8 sdks apple moved #"UISearchBarBackground" view one level deeper, so have will need to look at subviews of the child-views as bellow,
for (UIView *subview in searchBar.subviews) {
for(UIView* grandSonView in subview.subviews){
if ([grandSonView isKindOfClass:NSClassFromString(#"UISearchBarBackground")]) {
grandSonView.alpha = 0.0f;
}else if([grandSonView isKindOfClass:NSClassFromString(#"UISearchBarTextField")] ){
NSLog(#"Keep textfiedld bkg color");
}else{
grandSonView.alpha = 0.0f;
}
}//for cacheViews
}//subviews
Set background image
UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:searchBar.bounds];
backgroundView.image = [UIImage imageNamed:#"xxxx.png"];
[searchBar insertSubview:backgroundView atIndex:1]; // at index 1 but not 0
[backgroundView release];
One liner:
[[self.theSearchBar.subviews objectAtIndex:0] removeFromSuperview];

Resources