Search code examples
iosobjective-cuitableviewuisearchbaruisearchcontroller

UISearchController searchBar don't disappear when push viewcontroller


I'm using a UISearchController inside ma UIViewcontroller that contains a UITableView, I do this in viewDidLoad:

    self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
    self.searchController.delegate = self;
    self.searchController.searchResultsUpdater = self;
    self.searchController.searchBar.delegate = self;
    self.searchController.dimsBackgroundDuringPresentation = NO;
    self.searchController.hidesNavigationBarDuringPresentation = NO;
    self.definesPresentationContext = NO;

when I push a button in the navbar i do this:

    self.tableView.contentOffset = CGPointMake(0, 0 - self.tableView.contentInset.top);
    self.tableView.tableHeaderView = self.searchController.searchBar;
    [self.searchController.searchBar becomeFirstResponder];

all works fine, but when I push a UIViewController from a row in the UITableView results the UISearchBar stay there and display also on the content of the other view, how can i dismiss when I push a view and present when I go back to see the result of the UITableView?

thanks

EDIT:

this is the code of the method didSelectRowAtIndexPath:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
    DetailListController *detailList = [[DetailListController alloc] init];
    [self.navigationController pushViewController:detailList animated:YES];
}

Solution

  • Try this standard way suggested by apple:

    Declare the properties:

    @interface APLMainTableViewController () <UISearchBarDelegate, UISearchControllerDelegate, UISearchResultsUpdating>
    
    @property (nonatomic, strong) UISearchController *searchController;
    
    // our secondary search results table view
    @property (nonatomic, strong) APLResultsTableController *resultsTableController;
    
    // for state restoration
    @property BOOL searchControllerWasActive;
    @property BOOL searchControllerSearchFieldWasFirstResponder;
    
    @end
    
    
    
        - (void)viewDidLoad {
        [super viewDidLoad];
    
        _resultsTableController = [[APLResultsTableController alloc] init];
        _searchController = [[UISearchController alloc] initWithSearchResultsController:self.resultsTableController];
        self.searchController.searchResultsUpdater = self;
        [self.searchController.searchBar sizeToFit];
        self.tableView.tableHeaderView = self.searchController.searchBar;
    
        // we want to be the delegate for our filtered table so didSelectRowAtIndexPath is called for both tables
        self.resultsTableController.tableView.delegate = self;
        self.searchController.delegate = self;
        self.searchController.dimsBackgroundDuringPresentation = NO; // default is YES
        self.searchController.searchBar.delegate = self; // so we can monitor text changes + others
    
        // Search is now just presenting a view controller. As such, normal view controller
        // presentation semantics apply. Namely that presentation will walk up the view controller
        // hierarchy until it finds the root view controller or one that defines a presentation context.
        //
        self.definesPresentationContext = YES;  // know where you want UISearchController to be displayed
    }
    
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
    
        // restore the searchController's active state
        if (self.searchControllerWasActive) {
            self.searchController.active = self.searchControllerWasActive;
            _searchControllerWasActive = NO;
    
            if (self.searchControllerSearchFieldWasFirstResponder) {
                [self.searchController.searchBar becomeFirstResponder];
                _searchControllerSearchFieldWasFirstResponder = NO;
            }
        }
    }
    
    
    #pragma mark - UISearchBarDelegate
    
    - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
        [searchBar resignFirstResponder];
    }
    
    
    #pragma mark - UISearchControllerDelegate
    
    // Called after the search controller's search bar has agreed to begin editing or when
    // 'active' is set to YES.
    // If you choose not to present the controller yourself or do not implement this method,
    // a default presentation is performed on your behalf.
    //
    // Implement this method if the default presentation is not adequate for your purposes.
    //
    - (void)presentSearchController:(UISearchController *)searchController {
    
    }
    
    - (void)willPresentSearchController:(UISearchController *)searchController {
        // do something before the search controller is presented
    }
    
    - (void)didPresentSearchController:(UISearchController *)searchController {
        // do something after the search controller is presented
    }
    
    - (void)willDismissSearchController:(UISearchController *)searchController {
        // do something before the search controller is dismissed
    }
    
    - (void)didDismissSearchController:(UISearchController *)searchController {
        // do something after the search controller is dismissed
    }
    

    and here comes the interesting part: Use the below code to restore the status when you comeback from the detail view

    #pragma mark - UIStateRestoration
    
    // we restore several items for state restoration:
    //  1) Search controller's active state,
    //  2) search text,
    //  3) first responder
    
    NSString *const ViewControllerTitleKey = @"ViewControllerTitleKey";
    NSString *const SearchControllerIsActiveKey = @"SearchControllerIsActiveKey";
    NSString *const SearchBarTextKey = @"SearchBarTextKey";
    NSString *const SearchBarIsFirstResponderKey = @"SearchBarIsFirstResponderKey";
    
    - (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
        [super encodeRestorableStateWithCoder:coder];
    
        // encode the view state so it can be restored later
    
        // encode the title
        [coder encodeObject:self.title forKey:ViewControllerTitleKey];
    
        UISearchController *searchController = self.searchController;
    
        // encode the search controller's active state
        BOOL searchDisplayControllerIsActive = searchController.isActive;
        [coder encodeBool:searchDisplayControllerIsActive forKey:SearchControllerIsActiveKey];
    
        // encode the first responser status
        if (searchDisplayControllerIsActive) {
            [coder encodeBool:[searchController.searchBar isFirstResponder] forKey:SearchBarIsFirstResponderKey];
        }
    
        // encode the search bar text
        [coder encodeObject:searchController.searchBar.text forKey:SearchBarTextKey];
    }
    
    - (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
        [super decodeRestorableStateWithCoder:coder];
    
        // restore the title
        self.title = [coder decodeObjectForKey:ViewControllerTitleKey];
    
        // restore the active state:
        // we can't make the searchController active here since it's not part of the view
        // hierarchy yet, instead we do it in viewWillAppear
        //
        _searchControllerWasActive = [coder decodeBoolForKey:SearchControllerIsActiveKey];
    
        // restore the first responder status:
        // we can't make the searchController first responder here since it's not part of the view
        // hierarchy yet, instead we do it in viewWillAppear
        //
        _searchControllerSearchFieldWasFirstResponder = [coder decodeBoolForKey:SearchBarIsFirstResponderKey];
    
        // restore the text in the search field
        self.searchController.searchBar.text = [coder decodeObjectForKey:SearchBarTextKey];
    }
    
    @end