Search code examples
iosios7uicollectionviewuisearchbaruisearchresultscontroller

UISearchBar in a UICollectionView disappears when using UISearchDisplayController


I have a UISearchBar added as a subview to a UICollectionView, and attached to a UISearchDisplayController.

I set it up in viewDidLoad:

self.searchController = [[UISearchDisplayController alloc] initWithSearchBar:self.searchBar
                                                          contentsController:self];
self.searchController.delegate = self;
self.searchController.searchResultsDataSource = self;
self.searchController.searchResultsDelegate = self;

[self.collectionView addSubview:self.searchBar];

When I push another view controller to the navigation controller then pop it, the search bar disappears. This only happens if the collection view is scrolled down enough for the search bar to be hidden. Also, even though the search bar disappears, tapping the white space where it's supposed to be activates the search display controller attached to it.

This happens only on iOS 7, and if I remove the search display controller the search bar will not disappear.

One more thing worth mentioning. When the search bar has disappeared, if I push another view controller then pop it, the bar will be visible again.

Apparently this is a bug of UISearchDisplayController on iOS 7, so any ideas on how to work around it?


Solution

  • I ended up implementing UISearchDisplayController on my own. Here's my code.

    ZBNSearchDisplayController.h

    @protocol ZBNSearchDisplayDelegate;
    
    @interface ZBNSearchDisplayController : NSObject<UISearchBarDelegate>
    
    - (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController;
    - (void)setActive:(BOOL)visible animated:(BOOL)animated;
    
    @property(nonatomic,assign) id<ZBNSearchDisplayDelegate> delegate;
    @property(nonatomic, getter = isActive) BOOL active;
    @property(nonatomic, readonly) UISearchBar *searchBar;
    @property(nonatomic, readonly) UIViewController *searchContentsController;
    @property(nonatomic, readonly) UITableView *searchResultsTableView;
    @property(nonatomic, assign) id<UITableViewDataSource> searchResultsDataSource;
    @property(nonatomic, assign) id<UITableViewDelegate> searchResultsDelegate;
    
    @end
    
    @protocol ZBNSearchDisplayDelegate <NSObject>
    
    @optional
    
    - (void)searchDisplayControllerWillBeginSearch:(ZBNSearchDisplayController *)controller;
    - (void)searchDisplayControllerDidBeginSearch:(ZBNSearchDisplayController *)controller;
    - (void)searchDisplayControllerWillEndSearch:(ZBNSearchDisplayController *)controller;
    - (void)searchDisplayControllerDidEndSearch:(ZBNSearchDisplayController *)controller;
    - (void)textDidChange:(NSString *)searchText;
    - (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope;
    
    @end
    

    ZBNSearchDisplayController.m

    #import "ZBNSearchDisplayController.h"
    
    @implementation ZBNSearchDisplayController
    
    - (id)initWithSearchBar:(UISearchBar *)searchBar contentsController:(UIViewController *)viewController {
        self = [super init];
    
        if (self) {
            _searchBar = searchBar;
            _searchBar.delegate = self;
            _searchContentsController = viewController;
    
            CGFloat y = 64.0f;
            CGFloat height = _searchContentsController.view.frame.size.height - y;
    
            _searchResultsTableView = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, y, _searchContentsController.view.frame.size.width, height)];
            _searchResultsTableView.scrollsToTop = NO;
        }
    
        return self;
    }
    
    - (void)setSearchResultsDataSource:(id<UITableViewDataSource>)searchResultsDataSource {
        _searchResultsTableView.dataSource = searchResultsDataSource;
    }
    
    - (void)setSearchResultsDelegate:(id<UITableViewDelegate>)searchResultsDelegate {
        _searchResultsTableView.delegate = searchResultsDelegate;
    }
    
    - (void)setActive:(BOOL)visible animated:(BOOL)animated {
        if (!visible) {
            [_searchBar resignFirstResponder];
            _searchBar.text = nil;
            _searchBar.showsCancelButton = NO;
        }
    
        if (visible && [self.delegate respondsToSelector:@selector(searchDisplayControllerWillBeginSearch:)]) {
            [self.delegate searchDisplayControllerWillBeginSearch:self];
        } else if (!visible && [self.delegate respondsToSelector:@selector(searchDisplayControllerWillEndSearch:)]) {
            [self.delegate searchDisplayControllerWillEndSearch:self];
        }
    
        [_searchContentsController.navigationController setNavigationBarHidden:visible animated:YES];
    
        float alpha = 0;
    
        if (visible) {
            [_searchContentsController.view addSubview:_searchResultsTableView];
            alpha = 1.0;
        }
    
        if ([_searchContentsController.view respondsToSelector:@selector(scrollEnabled)]) {
            ((UIScrollView *)_searchContentsController.view).scrollEnabled = !visible;
        }
    
        if (animated) {
            [UIView animateWithDuration:0.2 animations:^{
                _searchResultsTableView.alpha = alpha;
            } completion:^(BOOL finished) {
                self.active = visible;
            }];
        } else {
            _searchResultsTableView.alpha = alpha;
        }
    }
    
    #pragma mark - UISearchBarDelegate
    
    - (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope {
        if ([self.delegate respondsToSelector:@selector(searchBar:selectedScopeButtonIndexDidChange:)]) {
            [self.delegate searchBar:searchBar selectedScopeButtonIndexDidChange:selectedScope];
        }
    }
    
    - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
        if ([self.delegate respondsToSelector:@selector(textDidChange:)]) {
            [self.delegate textDidChange:searchText];
        }
    }
    
    - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
        [searchBar setShowsCancelButton:YES animated:YES];
        [self setActive:YES animated:YES];
        [_searchResultsTableView reloadData];
    }
    
    - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
        [_searchResultsTableView reloadData];
    }
    
    - (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
        [self setActive:NO animated:YES];
        [self.searchResultsTableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
    }
    
    @end