SearchBar disappears from headerview in iOS 7 - iphone

I have a tableview for showing a list of devices in my application. When viewWillAppear is called, I add the self.searchDisplayController.searchBar as a subview to a headerView. I then assign self.tableView.tableHeaderView = headerView. It looks like this:
I scroll the tableview down so that headerview goes out of view and then go to some other view controller by tapping on a cell. When I come back to this tableView, scroll up to the headerView, the searchBar becomes invisible, however on tapping the invisible area the searchDisplayController gets activated and the cancel button doesn't work. This happens for iOS 7 only. Why is this happening?
Note: It happens only if the headerView is out of the view when I come back to the tableViewController.

I've just had the same issue. When I go to debug into the delegate method of UISearchDisplayController at the end search state, the searchBar becomes a subview of an UIView, not the UITableView. Please see below code:
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller
{
//My Solution: remove the searchBar away from current super view,
//then add it as subview again to the tableView
UISearchBar *searchBar = controller.searchBar;
UIView *superView = searchBar.superview;
if (![superView isKindOfClass:[UITableView class]]) {
NSLog(#"Error here");
[searchBar removeFromSuperview];
[self.tableView addSubview:searchBar];
}
NSLog(#"%#", NSStringFromClass([superView class]));
}
My solution is remove the searchBar away from current super view, then add it as subview again to the tableView. I've already tested successfully.
Hope that help!
Regards

I have the exact same problem. the search bar is still there and can receive touch events. it is however not rendered. I believe the problem is in UISearchDisplaycontroller because it renders fine if I don't use UISearchDisplayController. I ended up writing a custom SearchDisplaycontroller to replace it. it is very basic and only does what I need.
use it is the same way as you would the normal UISearchDisplayController but self.searchDisplayController will not return anything. you will have to use another pointer to refer to the custom search display controller.
looks like a big ugly work around, but the only one that worked for me. keen to hear of alternatives.
#protocol SearchDisplayDelegate;
#interface SearchDisplayController : NSObject<UISearchBarDelegate>
- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController;
#property(nonatomic,assign) id<SearchDisplayDelegate> delegate;
#property(nonatomic,getter=isActive) BOOL active; // configure the view controller for searching. default is NO. animated is NO
- (void)setActive:(BOOL)visible animated:(BOOL)animated; // animate the view controller for searching
#property(nonatomic,readonly) UISearchBar *searchBar;
#property(nonatomic,readonly) UIViewController *searchContentsController; // the view we are searching (often a UITableViewController)
#property(nonatomic,readonly) UITableView *searchResultsTableView; // will return non-nil. create if requested
#property(nonatomic,assign) id<UITableViewDataSource> searchResultsDataSource; // default is nil. delegate can provide
#property(nonatomic,assign) id<UITableViewDelegate> searchResultsDelegate;
#end
#protocol SearchDisplayDelegate <NSObject>
// implement the protocols you need
#optional
#end
the implementation
#implementation SearchDisplayController {
UISearchBar *_searchBar;
UIViewController *_viewController;
UITableView *_searchResultsTableView;
UIView *_overLay;
}
- (void)dealloc {
[_searchBar release];
[_searchResultsTableView release];
[_overLay release];
[super dealloc];
}
- (UIViewController *)searchContentsController {
return _viewController;
}
- (UITableView *)searchResultsTableView {
return _searchResultsTableView;
}
- (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController {
self = [super init];
if (self) {
_searchBar = [searchBar retain];
_searchBar.delegate = self;
_viewController = viewController;
_searchResultsTableView = [[UITableView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(_searchBar.frame), _viewController.view.frame.size.width, _viewController.view.frame.size.height - CGRectGetMaxY(_searchBar.frame))];
_overLay = [[UIView alloc]initWithFrame:_searchResultsTableView.frame];
_overLay.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(overLayTapped)];
[_overLay addGestureRecognizer:tap];
[tap release];
}
return self;
}
- (void)setSearchResultsDataSource:(id<UITableViewDataSource>)searchResultsDataSource {
_searchResultsTableView.dataSource = searchResultsDataSource;
}
- (void)setSearchResultsDelegate:(id<UITableViewDelegate>)searchResultsDelegate {
_searchResultsTableView.delegate = searchResultsDelegate;
}
- (void)overLayTapped {
[self setActive:NO animated:YES];
[_searchBar resignFirstResponder];
_searchBar.text = nil;
_searchBar.showsCancelButton = NO;
}
- (void)setActive:(BOOL)visible animated:(BOOL)animated {
UIView *viewToAdd = nil;
if (!_searchBar.text.length) {
viewToAdd = _overLay;
} else {
viewToAdd = _searchResultsTableView;
}
float a = 0;
if (visible) {
[_viewController.view addSubview:viewToAdd];
a = 1.0;
}
if ([_viewController.view respondsToSelector:#selectore(scrollEnabled)]) {
((UIScrollView *)_viewController.view).scrollEnabled = !visible;
}
if (animated) {
[UIView animateWithDuration:0.2 animations:^{
_overLay.alpha = a;
_searchResultsTableView.alpha = a;
}];
} else {
_overLay.alpha = a;
_searchResultsTableView.alpha = a;
}
}
- (void)setActive:(BOOL)active {
[self setActive:active animated:YES];
}
#pragma mark - UISearchBar delegate protocols
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
[self setActive:YES animated:YES];
searchBar.showsCancelButton = YES;
[_searchResultsTableView reloadData];
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar {
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
[_searchResultsTableView reloadData];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[self overLayTapped];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
if (searchText.length) {
[_overLay removeFromSuperview];
[_viewController.view addSubview:_searchResultsTableView];
} else {
[_searchResultsTableView removeFromSuperview];
[_viewController.view addSubview:_overLay];
}
[_searchResultsTableView reloadData];
}
#end
Update: on how to use this progammatically
declare an ivar
SearchDisplayController *mySearchDisplayController;
initialize it programmatically
mySearchDisplayController = [[SearchDisplayController alloc]initWithSearchBar:mySearchBar contentsController:self];
adding the searchbar to your tableview
self.tableView.headerView = mySearchBar;
use mySearchDisplayController as reference to the custon class instead on self.searchDisplayController.

In my case, the table view that held the search display controller's search bar in its header view was being reloaded almost as soon as the view appeared. It was at this point that the search bar would cease to render. When I scrolled the table, it would reappear. It's also worth mentioning that my table contained a UIRefreshControl and was not a UITableViewController subclass.
My fix involved setting the search display controller active and then inactive very quickly just before after loading the table (and ending the refresh control refreshing):
[self.tableView reloadData];
[self.refreshControl endRefreshing];
[self.searchDisplayController setActive:YES animated:NO];
[self.searchDisplayController setActive:NO];
A bit of a hack but it works for me.

Using the debugger, I've found that the UISearchBar is initially a child view of the tableHeaderView - but when it disappears, it has become a child of the tableView itself. This has probably been done by UISearchDisplayController somehow... So I did the following hack to simply return the UISearchBar to the header view:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(!self.searchDisplayController.isActive && self.searchBar.superview != self.tableView.tableHeaderView) {
[self.tableView.tableHeaderView addSubview:self.searchBar];
}
}
Seems to work fine on iOS 7 as well as 6 :)
(checking that the searchDisplayController isn't active is necessary, otherwise the sarch bar disappears during search)

I endorse Phien Tram's answer. Please upvote it. I don't have enough points myself.
I had a similar problem where a search bar loaded from storyboard would disappear when I repeatedly tapped it, invoking and dismissing search. His solution repairs the problem.
There seems to be a bug where repeated invocation and dismissal of the search display controller doesn't always give the search bar back to the table view.
I will say I'm uncomfortable with the solution's dependence on the existing view hierarchy. Apple seems to reshuffle it with every major release. This code may break with iOS 8.
I think a permanent solution will require a fix by Apple.

I had the same issue and I could fix it calling next line after creating the UISearchDisplayController
[self performSelector:#selector(setSearchDisplayController:) withObject:displayController];
My viewDidLoad function look like this:
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 44)];
searchBar.placeholder = NSLocalizedString(#"Search", #"Search");
UISearchDisplayController *displayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar contentsController:self];
displayController.delegate = self;
displayController.searchResultsDataSource = self;
displayController.searchResultsDelegate = self;
[self performSelector:#selector(setSearchDisplayController:) withObject:displayController];
self.tableView.contentOffset = CGPointMake(0, 44);
self.tableView.tableHeaderView = searchBar;
Thanks to this answer: https://stackoverflow.com/a/17324921/1070393

Use UISearchBar above UITableView,Then make IBOutlet for and connect them with file's owner to UISearchbar
Example- .h file
#import <UIKit/UIKit.h>
#interface LocationViewController : UIViewController<UISearchBarDelegate>
{
BOOL IsSearchOn;
}
#property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
#property (strong, nonatomic) IBOutlet UITableView *TBVLocation;
.m file
#pragma mark -
#pragma mark UISearchBar Delegate Methods
-(void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self.searchResult removeAllObjects];
if(searchText.length == 0)
{
IsSearchOn=NO;
// [filteredTableData removeAllObjects];
[self.searchBar resignFirstResponder];
// [self .tblView reloadData];
}
else
{
IsSearchOn=YES;
if(searchText != nil && ![searchText isEqualToString:#""])
{
/* NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:#"SELF contains[c] %#", searchText];
self.searchResult = [NSMutableArray arrayWithArray: [searchArray filteredArrayUsingPredicate:resultPredicate]];*/
for(int i=0;i<[[arrCountryList valueForKey:#"country_name"] count];i++)
{
NSRange titleRange = [[[[arrCountryList valueForKey:#"country_name"] objectAtIndex:i] lowercaseString] rangeOfString:[searchText lowercaseString]];
if(titleRange.location != NSNotFound)
[self.searchResult addObject:[arrCountryList objectAtIndex:i]];
}
[TBVLocation reloadData];
}
}
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
}
-(void)searchBarCancelButtonClicked:(UISearchBar *) searchBar
{
[searchBar resignFirstResponder];
IsSearchOn=NO;
searchBar.text = nil;
[TBVLocation reloadData];
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
[searchBar resignFirstResponder];
return YES;
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
searchBar.showsCancelButton = YES;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
// IsSearchOn=YES;
}
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
IsSearchOn=NO;
searchBar.showsCancelButton = NO;
[TBVLocation reloadData];
[searchBar resignFirstResponder];
}
It will work like charm.

I've faced similar problem and after some digging, I've found that this is a bug in UISearchBar hierarchy. This hacky solution worked for me in iOS 7, but be aware that this may break in future iOS versions:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIView *buggyView = [self.searchDisplayController.searchBar.subviews firstObject];
// buggyView bounds and center are incorrect after returning from controller, so adjust them.
buggyView.bounds = self.searchDisplayController.searchBar.bounds;
buggyView.center = CGPointMake(CGRectGetWidth(buggyView.bounds)/2, CGRectGetHeight(buggyView.bounds)/2);
}

I had the same problem and tested some of the solutions proposed here in this thread, but they didn't solve the problem for me.
Previously, I added and configured the UISearchBar in the
- (void)viewDidLoad
method of my ViewController in code.
UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:searchBarView.frame];
searchBar.delegate = self;
searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
ect...
What solved this issue for me was that I added a UISearchbar in the InterfaceBuilder, created an outlet in my ViewController and added this UISearchBar to my UISearchDisplayController.
self.searchDisplayController = [[UISearchDisplayController alloc] initWithSearchBar:searchBar(<--outlet) contentsController:self];
hope this might also help some people

Related

UISearchBar placeholder aligning and cropping in iOS 7

In iOS 7 UISearchbar placeholder center-aligned and overlay the bookmarks button until search bar doesn't selected:
When it selected, it looks as expected:
I need it looks this way all the time. Thank you.
NEW SOLUTION:
//
// WPViewController.m
// test
//
// Created by VASANTH K on 02/01/14.
//
//
#import "WPViewController.h"
#interface WPViewController ()
{
UILabel *lableCopy;
}
#end
#implementation WPViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//[self fixSearchBar:searchBar];
// Do any additional setup after loading the view, typically from a nib.
self.searchBar.delegate=self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.searchBar resignFirstResponder];
//[self fixSearchBar:searchBar];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self fixSearchBar:self.searchBar];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)searchBarTextDidBeginEditing:(UISearchBar *)search
{
[self fixSearchBar:self.searchBar];
}
-(void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
[self fixSearchBar:self.searchBar];
}
-(void)fixSearchBar:(UISearchBar*)searchBar
{
UITextField *searchField = [searchBar valueForKey:#"_searchField"];
// [searchField setValue:[UIColor blueColor] forKeyPath:#"_placeholderLabel.textColor"];
UILabel *lable=[searchField valueForKey:#"_placeholderLabel"];
if(!lableCopy)
{
lableCopy=[[UILabel alloc]initWithFrame:lable.frame];
lableCopy.font=lable.font;
[lableCopy setText:lable.text];
[lableCopy setTextColor:lable.textColor];
UIButton *button;
for (UIView *view in [[[[searchBar.subviews objectAtIndex:0] subviews] objectAtIndex:1] subviews]) {
if([view isKindOfClass:[UIButton class]])
{
button=(UIButton*)view;
break;
}
}
if(button)
{
//lable.hidden=YES;
CGRect newFrame=lable.frame;
newFrame.size.width=button.frame.origin.x-lable.frame.origin.x;
lableCopy.frame=newFrame;
[lableCopy adjustsFontSizeToFitWidth];
//lableCopy.backgroundColor=[UIColor blackColor];
[searchField addSubview:lableCopy];
lableCopy.text=lable.text;
//lableCopy.textColor=[UIColor redColor];
}
}
for (UIView *view in [[searchBar.subviews objectAtIndex:0] subviews]) {
if([view isKindOfClass:[UITextField class]])
{
// NSLog(#"%#",view);
NSLog(#"TextFieldPresent==>%#",view);
if([view isFirstResponder])
{
lable.hidden=NO;
lableCopy.hidden=YES;
}
else
{
lable.hidden=YES;
lableCopy.hidden=NO;
}
break;
}
}
}
#end
This solution is just adding new UILable view and hide the existing placeholder to give the real feel of searchBar.Again redisplay the actual placeholder when search Bar became active.
This may be a temporary hack to fix that UI issue in IOS7.
OLD SOLUTION:
[searchField setValue:[NSNumber numberWithBool:YES] forKeyPath:#"_placeholderLabel.adjustsFontSizeToFitWidth"];
will not work in ios7 because the size of lable used for disaplay the content is enough to show the text, the problem is the label width bug of ios7. it fails to re-size the label width.
there is little bit hack to fix this.
UITextField *searchField = [searchBar valueForKey:#"_searchField"];
UILabel *lable=[searchBar valueForKey:#"_placeholderLabel"];
lable.font=[UIFont fontWithName:lable.font.fontName size:10.0];
calculate the font-size based upon the search bar width of your own. I also tried to change the width of particular label but it never work.
-(void)viewDidAppear:(BOOL)animated{
self.searchBar.placeholder=#"woord hier invoeren";
}
-(void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar{
self.searchBar.placeholder=#"woord hier invoeren.......";
}
I'm not here to give you a general solution but if you have a placeHolder to add, the dumbest and easy way to do it is by truncating the placeHolder yourself, so instead of
searchBar.placeholder = #"woord hier invoeren";
let it be
searchBar.placeholder = #"woord hier invo...";
i tried to mess with the private methods of apple but with no luck:
the searchBar subviews are :
-UISearchBarBackground.
-UISearchBarTextField.
leave the UISearchBarBackground aside
the subviews of the UISearchBarTextField instance are :
-_UISearchBarSearchFieldBackgroundView.
-UIImageView.
-UISearchBarTextFieldLabel.
what i went for is trying to mess with the rect (i emphasis on the word mess as these are private methods) of the UISearchBarTextFieldLabel coz i'm pretty sure that its frame ain't rendered right when the searchBar button is shown (bookmark), if you choose searchBar.showsBookmarkButton = NO; the placeHolder text will be truncated as expected.
It's up to you, save yourself sometime and go with the dumb solution but that gets things done, or delve even further.
keep up the good work.

IOS 5 MBProgressHUD disable tab bar buttons while loading data. (userInteractionEnabled = NO)

I use MBProgressHUD when loading data and user can press the another tab button during the process. MBProgressHUD only disable the view contents.
I checked other posts but didn't see anything helps me to disable the tab button.
I tried to set tabbaritem.userInteractionEnabled to NO but I couldn't find a way to access that. I can do it in storyboard but can't switch it back to YES.
My question is; from my viewController is there any way to access tabbarcontroller.tabbaritem.userInteractionEnabled ?
I use category:
UIViewController+MBProgressHUD.h
#import <UIKit/UIKit.h>
#class MBProgressHUD;
#interface UIViewController (MBProgressHUD)
- (MBProgressHUD *)showHUD;
- (MBProgressHUD *)showHUDFromTitle:(NSString *)title;
- (MBProgressHUD *)showHUDFromTitle:(NSString *)title completedImage:(BOOL)completedImage;
- (void)hideHUD;
#end
And UIViewController+MBProgressHUD.m
#import "UIViewController+MBProgressHUD.h"
#import <MBProgressHUD/MBProgressHUD.h>
#implementation UIViewController (MBProgressHUD)
- (MBProgressHUD *)showHUDFromTitle:(NSString *)title {
UIView *view;
if (self.tabBarController.view != nil) {
view = self.tabBarController.view;
} else if (self.navigationController.view != nil) {
view = self.navigationController.view;
} else {
view = self.view;
}
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:NO];
hud.labelText = title;
return hud;
}
- (MBProgressHUD *)showHUD {
return [self showHUDFromTitle:NSLocalizedString(#"Loading", #"Loading")];
}
- (MBProgressHUD *)showHUDFromTitle:(NSString *)title completedImage:(BOOL)completedImage {
MBProgressHUD *hud = [self showHUDFromTitle:title];
if (completedImage) {
UIImage *checkmarkImage = [UIImage imageNamed:#"37x-Checkmark"];
UIImageView *checkmarkImageView = [[UIImageView alloc] initWithImage:checkmarkImage];
hud.customView = checkmarkImageView;
hud.mode = MBProgressHUDModeCustomView;
} else {
hud.mode = MBProgressHUDModeText;
}
return hud;
}
- (void)hideHUD {
[MBProgressHUD hideAllHUDsForView:self.tabBarController.view animated:NO];
[MBProgressHUD hideAllHUDsForView:self.navigationController.view animated:NO];
[MBProgressHUD hideAllHUDsForView:self.view animated:NO];
}
Example:
[self showHUD];
[self hideHUD];
This is an easy way
[[[self tabBarController] tabBar] setUserInteractionEnabled:NO];
As stated in this link: How can I make the tabbar action hidden when the view is loading?
Works great with MBProgressHUD
Even more elegant to show the HUD from UITabBarController, since user interaction will be entirely controlled by MBProgressHUD until hideAnimated: is called:
// Show HUD from Tab Bar, to disable the tab bar items:
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.tabBarController.view
animated:YES];
// Do some time-consuming stuff:
...
// Hide HUD and enable tab bar items:
[hud hideAnimated:YES];

How to access the views of the MoreViewController and change their titles?

on language switch within my App, I need to access the views of the MoreViewController in a TabBar and change their titles.
Could anyone pls tell me how to do that?
Your help is much appreciated.
Cols
Here are some snippets that might work for you. Note that all of the below is subject to break on each and every new iOS release at it is not meant to be done.
Customizing the More view title as itself as well as the title while it is being edited by the user.
- (void)customizeTitleViewWithNavigationItem:(UINavigationItem *)navigationItem
{
VASSERT(navigationItem != nil, #"invalid navigationItem supplied", navigationItem);
UILabel *titleView = [[UILabel alloc] initWithFrame:CGRectZero];
titleView.backgroundColor = [UIColor clearColor];
titleView.font = [UIFont boldSystemFontOfSize:20.0f];
titleView.text = navigationItem.title;
[titleView sizeToFit];
navigationItem.titleView = titleView;
[titleView release];
}
This needs to be implemented within the UINavigationController's delegate;
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
if (navigationController == tabBarController_.moreNavigationController)
{
if ([viewController isKindOfClass:NSClassFromString(#"UIMoreListController")])
{
[self customizeTitleViewWithNavigationItem:viewController.navigationItem];
}
else
{
NSLog(#"viewController (%#) does not seem to be a UIMoreListController", viewController);
}
}
else
{
NSLog(#"navigationController (%#) does not seem to be the moreNavigationController", navigationController);
}
}
This needs to be implemented within the UITabBarController's delegate;
- (void)tabBarController:(UITabBarController *)controller willBeginCustomizingViewControllers:(NSArray *)viewControllers
{
//get the second view of the upcoming tabbar-controller
UIView *editView = [controller.view.subviews objectAtIndex:1];
//did we get what we expected, which is a UITabBarCustomizeView?
if (editView != nil && [editView isKindOfClass:NSClassFromString(#"UITabBarCustomizeView")])
{ //yes->get the navigation-view
UIView *navigationView = [editView.subviews objectAtIndex:0];
//is that a navigationBar?
if (navigationView != nil && [navigationView isKindOfClass:[UINavigationBar class]])
{ //yes->...
UINavigationBar *navigationBar = (UINavigationBar *)navigationView;
[self customizeTitleViewWithNavigationItem:navigationBar.topItem];
}
else
{
NSLog(#"the navigationView (%#) does not seem to be a navigationBar", navigationView);
}
}
else
{
NSLog(#"the editView (%#) does not seem to be a UITabBarCustomizeView", editView);
}
}
I was able to change the title of one of the tabBar items for my 6th view controller (the last one in the more list) with the following code:
NSArray *vcs = [(UITabBarController *)self.window.rootViewController viewControllers];
[[vcs.lastObject tabBarItem] setTitle:#"New Title"];
Is this what you want to do?
After Edit: To change these titles after they are set up the first time, you need to re-set the viewControllers property of the tabBar controller. In this code example, I connected a button in my 6th view controller to an action method that changes the titles of 3 of my controllers, 2 in the more list and one in the regular list.
-(IBAction)changeNames:(id)sender {
UITabBarController *tbc = (UITabBarController *)[[UIApplication sharedApplication] delegate].window.rootViewController;
NSArray *vcs = tbc.viewControllers;
[[vcs.lastObject tabBarItem] setTitle:#"New Title"];
[[[vcs objectAtIndex:4] tabBarItem] setTitle:#"New VC"];
[[[vcs objectAtIndex:3] tabBarItem] setTitle:#"New VC2"];
tbc.viewControllers = tbc.viewControllers;
}

Changing the navigationbar color on the Edit screen of the More section

I am able to change the navbar color of the More navigationcontroller via:
stTabBarController.moreNavigationController.navigationBar.tintColor = [UIColor colorWithRed:(102.0/255.0) green:(20.0/255.0) blue:(11.0/255.0) alpha:1];
but when I click the Edit button, the Configure screen appears and the navbar color is the default blue. How can I change this color?
Solved it:
#pragma mark UITabBarControllerDelegate
- (void)tabBarController:(UITabBarController *)controller willBeginCustomizingViewControllers:(NSArray *)viewControllers {
UIView *editViews = [controller.view.subviews objectAtIndex:1];
UINavigationBar *editModalNavBar = [editViews.subviews objectAtIndex:0];
editModalNavBar.tintColor = [UIColor colorWithRed:(102.0/255.0) green:(20.0/255.0) blue:(11.0/255.0) alpha:1];
}
To anyone else with this question, in order for Sheehan Alam's solution to work, you need to make sure you set the tabBarController's delegate to self within the viewDidLoad method like so:
- (void)viewDidLoad {
...
self.delegate = self;
...
}
Then you need to make sure your tabBarController conforms to the UITabBarControllerDelegate protocol like so:
#interface TabBarController : UITabBarController <UITabBarControllerDelegate> {
...
}
Otherwise the method he's overriding won't be called.
#Sheehan Alam solution did not work for me (working on iOS 8). Anyway I got 2/3 of the solution from his answers. I am posting this to improve the answer.
#prama mark - UITabBarControllerDelegate
- (void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray *)viewControllers {
UIView *editViews = [tabBarController.view.subviews objectAtIndex:1];
for (UIView * view in [editViews subviews]) {
if ([view isKindOfClass:[UINavigationBar class]]) {
UINavigationBar *editNavBar = (UINavigationBar *)view;
editNavBar.barTintColor = [UIColor redColor];
}
}
}

UISearchDisplayController with no results tableView?

Usually, a UISearchDisplayController, when activated, dims the tableView and focuses the searchBar. As soon as you enter text into the searchBar, it creates a searchResultsTableView that displays between the searchBar and the keyboard. The searchDisplayController's delegate gets called when this second UITableView is loaded/shown/hidden/unloaded. Usually it shows live search results or autocompletion entries while typing.
In my app, I want to search a webservice and I don't want to call the webservice for each letter the user enters. Therefore, I want to entirely disable the searchResultsTableView and keep the dimmed black overlay while he enters text. I would then trigger the search (with a loading screen) once he hits the search button.
Just returning zero rows for the searchResultsTableView doesn't look nice since it displays an empty searchResultsTableView with a "no results" message. I tried to hide the table when it appears (searchDisplayController:didLoadSearchResultsTableView:) which works, but the blacked dimmed overlay is also hidden so that the underlying tableView is completely visible again.
Any ideas besides recreating the UISearchDisplayController functionality from scratch?
here is a little trick that i just figured out
and also you have to return 0 results while editing searchstring
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
savedSearchTerm = searchString;
[controller.searchResultsTableView setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.8]];
[controller.searchResultsTableView setRowHeight:800];
[controller.searchResultsTableView setScrollEnabled:NO];
return NO;
}
- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
// undo the changes above to prevent artefacts reported below by mclin
}
i think you'll figure out what to do next
Have you tried this:
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(_lookup:) object:nil];
[self performSelector:#selector(_lookup:) withObject:txt afterDelay:0.20];
This way, if the user types another char within 1/5sec, you only make one web call.
Nothing of the above seemed to work well in the end, so I came up with the following (you have to call removeTableHeader when you are ready to display your results):
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
[self setTableHeader];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
[self setTableHeader];
}
- (void)setTableHeader {
UIView *headerView = [[UIView alloc] initWithFrame:self.searchDisplayController.searchResultsTableView.frame];
headerView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.8];
[self.searchDisplayController.searchResultsTableView setBackgroundColor:[UIColor clearColor]];
[self.searchDisplayController.searchResultsTableView setScrollEnabled:NO];
[self.searchDisplayController.searchResultsTableView setTableHeaderView:headerView];
[headerView release];
}
- (void)removeTableHeader {
[self.searchDisplayController.searchResultsTableView setBackgroundColor:[UIColor whiteColor]];
[self.searchDisplayController.searchResultsTableView setScrollEnabled:YES];
[self.searchDisplayController.searchResultsTableView setTableHeaderView:nil];
}
Obviously, it make the table transparent, adds a black/translucent table header with the same size as the table, and disables scrolling on the table so you cannot get above or past the header. As a bonus, you could add something to the header view ('please wait...' or an activity indicator).
Had the same problem as you, I handled it by a) setting the alpha of the searchResultsTableView to 0 when beginning searching, and then by b) adding/removing the overlayView to the viewController's view. Works like a charm for me.
#interface MyViewController()
//...
#property(nonatomic, retain) UIView *overlayView;
//...
#end
#implementation MyViewController
#synthesize overlayView = _overlayView;
//...
- (void)viewDidLoad
{
//...
//define your overlayView
_overlayView = [[UIView alloc] initWithFrame:CGRectMake(0, 44, 320, 480)];
_overlayView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.8];
}
//hide the searchResultsTableView
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
self.searchDisplayController.searchResultsTableView.alpha = 0.0f;
}
//when ending the search, hide the overlayView
- (void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
[_overlayView removeFromSuperview];
}
//depending on what the user has inputed, add or remove the overlayView to the view of the current viewController
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
if ([searchString length]>0)
{
[self.view addSubview:_overlayView];
}
else
{
[_overlayView removeFromSuperview];
}
return NO;
}
#end
it should be sufficient to implement the following method in your UISearchDisplayDelegate (which usually is your custom UITableViewController subclass)
- (BOOL) searchDisplayController: (UISearchDisplayController *) controller shouldReloadTableForSearchString: (NSString *) searchString
{
[self startMyCustomWebserviceSearchAsBackgroundProcessForString: searchString]; //starts new NSThread
return NO;
}
have you tried this?
Based on user182820's code below is my version. I hide the UISearchDisplayController's table view. When a character is entered in the search box I place a 'dimmed view' so it looks like UISearchDisplayController's 'dimmed view' never went away and then remove it when the search is finished. If you enter some characters and press cancel, the table view briefly goes all white and I don't know how to get around this.
- (void)viewDidLoad {
...
tableViewMask=[UIView new];
tableViewMask.backgroundColor = [UIColor blackColor];
tableViewMask.alpha = 0.8;
}
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller{
tableViewMask.frame=CGRectMake(self.tableView.frame.origin.x, self.tableView.frame.origin.y+controller.searchBar.frame.size.height, self.tableView.frame.size.width, self.tableView.frame.size.height-controller.searchBar.frame.size.height);
controller.searchResultsTableView.hidden=YES;
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller{
[tableViewMask removeFromSuperview];
}
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString{
if (searchString.length==0)
[tableViewMask removeFromSuperview];
else
[self.tableView addSubview:tableViewMask];
[searchText autorelease];
searchText=[searchString retain];
return NO;
}
What about just doing it as simple as this:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
self.searchDisplayController.searchResultsTableView.hidden=YES;
return YES;
}
Works fine for me..
I foud a better way, since there is a bug with the "best answer" - the separator and the "No Results" will be shown when scrolling the black background table.
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
controller.searchResultsTableView.backgroundColor = [UIColor blackColor];
controller.searchResultsTableView.alpha = 0.8;
controller.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
for(UIView *subview in tableView.subviews) {
if([subview isKindOfClass:UILabel.class]) {
subview.hidden = YES;
}
}
return NO;
}
- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar {
self.searchDisplayController.searchResultsTableView.backgroundColor = [UIColor whiteColor];
self.searchDisplayController.searchResultsTableView.alpha = 1;
self.searchDisplayController.searchResultsTableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
for(UIView *subview in tableView.subviews) {
if([subview isKindOfClass:UILabel.class]) {
subview.hidden = NO;
}
}
// search results and reload data ....
}
All of the existing answers are overly complicated. You can get away by just hiding the results table view immediately.
-(void)searchDisplayController:(UISearchDisplayController *)controller didShowSearchResultsTableView:(UITableView *)tableView
{
tableView.hidden = YES;
}
I think I found a better implementation for this problem. All the previous answers correctly show a dimmed view identical to what the UITableView looks like before a search, but each solution lacks the functionality to tap the area in order to cancel the search.
For that reason I think this code works better.
First of all, create a BOOL such as searchButtonTapped to indicate whether the search button was tapped. By default it is NO.
Then:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
if (!searchButtonTapped) {
// To prevent results from being shown and to show an identical look to how the tableview looks before a search
[controller.searchResultsTableView setBackgroundColor:[UIColor clearColor]];
[controller.searchResultsTableView setRowHeight:160];
self.searchDisplayController.searchResultsTableView.scrollEnabled = NO;
} else {
// Restore original settings
[controller.searchResultsTableView setBackgroundColor:[UIColor whiteColor]];
[controller.searchResultsTableView setRowHeight:44];
self.searchDisplayController.searchResultsTableView.scrollEnabled = YES;
}
return YES;
}
This should be clear now based on the other answers. Make sure to also restore the original settings when the user taps on the Search button.
Furthermore, in the cellForIndexPath method add:
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.8];
In order to create the same dimmed view that is shown before text is entered. Make sure you apply these properties to the right cell, i.e., check which UITableView is active and that the user has not tapped the Search button.
Then, crucially, in didSelectRowAtIndexPath:
if (tableView == self.searchDisplayController.searchResultsTableView) {
if (searchButtonTapped) {
// Code for when the user select a row after actually having performed a search
{
else
[self.searchDisplayController setActive:NO animated:YES];
Now the user can tap the dimmed area, which will not result in a visible selection of a UITableViewCell, but instead cancels the search.