UISearchDisplayController with no results tableView?

25,968

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?

Share:
25,968
Zargony
Author by

Zargony

Software engineer (Rust, Ruby, JS, C), technology enthusiast, Mac user, self-employed, hobby photographer.

Updated on July 09, 2022

Comments

  • Zargony
    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
    Zargony almost 15 years
    This prevents the searchDisplayController from sending [searchResultsTableView reload], but unfortunately the searchResultsTableView is still displayed ("no results" message)
  • xoconoxtle
    xoconoxtle almost 15 years
    in this case i am afraid, that the default behaviour of the UISearchDisplayController can't be modified... sorry
  • Zargony
    Zargony almost 15 years
    By 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
    Zargony over 14 years
    Exactly what I was looking for. Thanks a lot!
  • mclin
    mclin over 13 years
    Works 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
    Chris almost 13 years
    Also worth putting 'controller.searchResultsTableView.scrollEnabled = NO;' in there too
  • jowie
    jowie over 12 years
    Brilliant 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
    ultravelocity over 12 years
    This sorta works, but you can't click on the header to dismiss
  • Frantic
    Frantic almost 12 years
    Few other points to keep in mind: (1) tap on this table wouldn't result in UISearchDisplayController being dismissed (I had to use UITapGestureRecognizer). (2) on iPad background color alpha should be ~0.5
  • elsurudo
    elsurudo over 11 years
    I like this solution better than the accepted answer; thanks! Much cleaner
  • Thom
    Thom over 11 years
    With 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
    Jeff Mascia over 11 years
    This 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
    Besi over 11 years
    This 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
    Besi over 11 years
    Just a style-related remark. You might want to use showTableHeader instead of setTableHeader since it's not a real setter in this case.
  • Besi
    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
    Besi over 11 years
    I 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
    neilb about 10 years
    Using alpha 0.4 makes the tint look exactly the same on iOS7.