UISearchDisplayController with no results tableView?
Solution 1
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
Solution 2
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.
Solution 3
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
Solution 4
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).
Solution 5
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?
Zargony
Software engineer (Rust, Ruby, JS, C), technology enthusiast, Mac user, self-employed, hobby photographer.
Updated on July 09, 2022Comments
-
Zargony almost 2 years
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?
-
Zargony almost 15 yearsThis prevents the searchDisplayController from sending [searchResultsTableView reload], but unfortunately the searchResultsTableView is still displayed ("no results" message)
-
xoconoxtle almost 15 yearsin this case i am afraid, that the default behaviour of the UISearchDisplayController can't be modified... sorry
-
Zargony almost 15 yearsBy pure chance I noticed yesterday, that the YouTube app does it exactly like I am looking for. Unfortunately I didn't find any nice way yet (besides creating UISearchDisplayController).
-
Zargony over 14 yearsExactly what I was looking for. Thanks a lot!
-
mclin over 13 yearsWorks the first time for me, but if you search, click the x to clear and then enter more text, it shows all the rows with opaque black background and white dividing lines. I guessed it might be the the UITableCellViews, so I added this to you function and it worked: for (UIView *subview in self.searchDisplayController.searchResultsTableView.subviews) { [subview removeFromSuperview]; }
-
Chris almost 13 yearsAlso worth putting 'controller.searchResultsTableView.scrollEnabled = NO;' in there too
-
jowie over 12 yearsBrilliant solution. And +1 to @Chris too. Why Apple don't have this as a setting you can choose seems really stupid, considering it's exactly how the Maps app works.
-
ultravelocity over 12 yearsThis sorta works, but you can't click on the header to dismiss
-
Frantic almost 12 yearsFew other points to keep in mind: (1) tap on this table wouldn't result in
UISearchDisplayController
being dismissed (I had to useUITapGestureRecognizer
). (2) on iPad background color alpha should be ~0.5 -
elsurudo over 11 yearsI like this solution better than the accepted answer; thanks! Much cleaner
-
Thom over 11 yearsWith the object:nil, will the cancel call actually match? You're probably better off calling plain old [NSObject cancelPreviousPerformRequestsWithTarget:self] if you haven't got any other perform requests going on.
-
Jeff Mascia over 11 yearsThis solution is the cleanest and most effective I found. The main problem with other solutions here is that when the 'fake' shadow overlay is visible and you dismiss the search interface, iOS forces the tableView to become opaque and the screen quickly flashes white, which is ugly. That doesn't happen with this implementation. @chaiwalla, if you want to mimic default tap-to-dismiss behavior just add a UITapGestureRecognizer to the headerView and call setActive:animated: on searchDisplayController in the callback.
-
Besi over 11 yearsThis does only partially work, in my case the background is dimmed, and as soon as I start typing the dimmed background is removed and revealing the underlying tableview
-
Besi over 11 yearsJust a style-related remark. You might want to use
showTableHeader
instead ofsetTableHeader
since it's not a real setter in this case. -
Besi over 11 years+1 This is IMHO the most elegant solution. To fix @chaiwalla's remark I used a UIButton within the HeaderView and then call
[searchDisplayController setActive:NO]
for the IBAction, thus closing the search when touching this area. -
Besi over 11 yearsI tried this and ran into a few things. I generally find Barry's approach more elegant since it uses the existing results table view.
-
neilb about 10 yearsUsing alpha 0.4 makes the tint look exactly the same on iOS7.