Show UISearchController's SearchResultsController on SearchBar Tap

て烟熏妆下的殇ゞ 提交于 2019-11-29 23:49:33

When results are empty, UISearchController's viewController is still hidden. That's why we have to fiddle our way around using UISearchControllerDelegate's willPresentSearchController:

After initializing self.searchController make your ViewController conform to `UISearchControllerDelegate:

self.searchController.delegate = self;

Implement willPresentSearchController: in your ViewController:

- (void)willPresentSearchController:(UISearchController *)searchController
{
    dispatch_async(dispatch_get_main_queue(), ^{
        searchController.searchResultsController.view.hidden = NO;
    });
}

The async dispatch is necessary, because otherwise it will be overridden by the internal behavior. You could go fancy here and use an animation to have the table view fade in.

Additionally, implement didPresentSearchController: for sanity:

- (void)didPresentSearchController:(UISearchController *)searchController
{
    searchController.searchResultsController.view.hidden = NO;
}

I found that the other answers had flickering due to using dispatch_async. They used this so that their changes would be applied after the internal behavior of the search controller had completed, but this leaves a couple frames where the internal behavior is applied before it is overridden. Using KVO allowed me to immediately override the internal behavior without any flickering.

I also found that the other answers did not keep the search results controller visible when a user tapped the ⓧ button to clear the contents of the search bar, which seems incorrect to me.

- (void) viewDidLoad
{
    ...
    self.searchController.delegate = self;
    [self.searchController.searchResultsController.view addObserver:self forKeyPath:@"hidden" options:0 context:NULL];
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{    
    if ( object == self.searchController.searchResultsController.view &&
         [keyPath isEqualToString:@"hidden"] &&
         self.searchController.searchResultsController.view.hidden &&
         self.searchController.searchBar.isFirstResponder )
    {
        self.searchController.searchResultsController.view.hidden = NO;
    }
}

- (void) willPresentSearchController:(UISearchController *)searchController
{
    searchController.searchResultsController.view.hidden = NO;
}

- (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    if ( searchText.length == 0 )
        self.searchController.searchResultsController.view.hidden = NO;
}


- (void) searchBarTextDidEndEditing:(UISearchBar *)searchBar
{
    self.searchController.searchResultsController.view.hidden = YES;
}

Chris Vasselli's answer is the cleanest way to implement this.

Here it is in Swift 3

override func viewDidLoad() {
    super.viewDidLoad()

    searchController.delegate = self
    self.searchController.searchResultsController?.view.addObserver(self, forKeyPath: "hidden", options: [], context: nil)
}


override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

    if let someView: UIView = object as! UIView? {

        if (someView == self.searchController.searchResultsController?.view &&
            (keyPath == "hidden") &&
            (searchController.searchResultsController?.view.isHidden)! &&
            searchController.searchBar.isFirstResponder) {

            searchController.searchResultsController?.view.isHidden = false
        }

    }
}


func willPresentSearchController(_ searchController: UISearchController) {
    searchController.searchResultsController?.view.isHidden = false
}


func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

    if (searchText.characters.count == 0) {
        searchController.searchResultsController?.view.isHidden = false
    }
}


func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    searchController.searchResultsController?.view.isHidden = true
}

I think this method is better, be careful when searchBar is empty then preload tableview will disappear again.

UISearchBarDelegate

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
    if searchText.isEmpty {
        dispatch_async(dispatch_get_main_queue()) {
            self.searchController.searchResultsController?.view.hidden = false
        }
    }
}

func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
    dispatch_async(dispatch_get_main_queue()) {
        self.searchController.searchResultsController?.view.hidden = false
    }
}

UISearchControllerDelegate

func willPresentSearchController(searchController: UISearchController) {
    dispatch_async(dispatch_get_main_queue()) {
        self.searchController.searchResultsController?.view.hidden = false
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!