UISearchController: show results even when search bar is empty
Updated for iOS 13
From iOS13, we got system API support for this behaviour. You can set the property showsSearchResultsController = true
For iOS 12 and below
I am recently working on UISearchController
. I want to show search history in searchResultsController
when search bar is empty. So searchResultsController
needs to show up whenever UISearchController
gets presented.
Here, I use another solution to make the searchResultsController
always visible by overriding the hidden
property in a custom view.
for example, my searchResultsController
is a UITableViewController
. I create a VisibleTableView as a subclass of UITableView
, and then change the UITableView
custom class of searchResultsController
to VisibleTableView in xib or storyboard. This way, my searchResultsController
will never be hidden by UISearchController
.
The good things here:
Easier to implement than KVO.
No delay to show
searchResultsController
. Flipping the hidden flag in "updateSearchResults" delegate method works, but there is a delay to show thesearchResultsController
.It does't reset the hidden flag, so there is no UI gap/jumping between hidden and visible.
Swift 3 sample code:
class VisibleTableView: UITableView {
override var isHidden: Bool {
get {
return false
}
set {
// ignoring any settings
}
}
}
You can simply implement the UISearchResultsUpdating
protocol and set the results controller view to always show in updateSearchResultsForSearchController
:
func updateSearchResultsForSearchController(searchController: UISearchController) {
// Always show the search result controller
searchController.searchResultsController?.view.hidden = false
// Update your search results data and reload data
..
}
This works because the method is called even when the search bar is activated, without any text.
If your searchBar is active but has no text, the underlying tableView results are shown. That's the built-in behavior, and the reason why searchResultsController is hidden for that state.
To change the behavior when search is active but not filtering, you're going to have to show the searchResultsController when it is normally still hidden.
There may be a good way to accomplish this via <UISearchResultsUpdating>
and updateSearchResultsForSearchController:
. If you can solve it via the protocol, that's the preferred way to go.
If that doesn't help, you're left with hacking the built-in behavior. I wouldn't recommend or rely on it, and it's going to be fragile, but here's an answer if you choose that option:
Make sure your tableViewController conforms to
<UISearchControllerDelegate>
, and addself.searchController.delegate = self;
Implement
willPresentSearchController:
- (void)willPresentSearchController:(UISearchController *)searchController { dispatch_async(dispatch_get_main_queue(), ^{ searchController.searchResultsController.view.hidden = NO; }); }
This makes the
searchResultsController
visible after itsUISearchController
set it to hidden.Implement
didPresentSearchController:
- (void)didPresentSearchController:(UISearchController *)searchController { searchController.searchResultsController.view.hidden = NO; }
For a better way to work around the built-in behavior, see malhal's answer.