UISearchController: show results even when search bar is empty

前端 未结 14 2175
独厮守ぢ
独厮守ぢ 2020-12-23 13:27

As I understand, the default behaviour of UISearchController is:

  1. On tapping search bar, background is dimmed and \'cancel\' button is shown.
相关标签:
14条回答
  • 2020-12-23 13:29

    With tricky things like this I recommend the sledge hammer approach! That is to detect when something tries to make it hidden and when it does, change it back. This can be done via KVO (Key Value Observing). This will work no matter what, without having to handle all the intricacies of the search bar. Sorry the code is complicated but KVO is an older style API but my code follows recommend practice. In your SearchResultsViewController put this:

    static int kHidden;
    
    @implementation SearchResultsViewController
    
    -(void)viewDidLoad{
        [super viewDidLoad];
        [self.view addObserver:self
                       forKeyPath:@"hidden"
                          options:(NSKeyValueObservingOptionNew |
                                   NSKeyValueObservingOptionOld)
                          context:&kHidden];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary *)change
                           context:(void *)context {
        // if it was our observation
        if(context == &kHidden){
            // if the view is hidden then make it visible.
            if([[change objectForKey:NSKeyValueChangeNewKey] boolValue]){
                self.view.hidden = NO;
            }
        }
        else{
            // if necessary, pass the method up the subclass hierarchy.
            if([super respondsToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)]){
                [super observeValueForKeyPath:keyPath
                                     ofObject:object
                                       change:change
                                      context:context];
            }
        }
    }
    
    - (void)dealloc
    {
        [self.view removeObserver:self forKeyPath:@"hidden"];
    }
    
    // Here have the rest of your code for the search results table.
    
    @end
    

    This works in all cases including if the text is cleared.

    Lastly, to prevent the table doing an ugly fade to grey then to white when the search activates, use this:

    self.searchController.dimsBackgroundDuringPresentation = NO;
    
    0 讨论(0)
  • I have tried PetahChristian solution, the preload result did show up when we first focus the searchbar, but when we enter something then clear it, the preload results will not reappear.

    I came up with another solution. We only need to add a delegate into SearchResultsController and call it when our searchController.searchBar.text is empty. Something like this:

    SearchResultsController:

    protocol SearchResultsViewControllerDelegate {
       func reassureShowingList() -> Void
    }
    
    class FullSearchResultsViewController: UIViewController, UISearchResultsUpdating{
       var delegate: SearchResultsViewControllerDelegate?
       ...
       func updateSearchResultsForSearchController(searchController: UISearchController) {
        let query = searchController.searchBar.text?.trim()
        if query == nil || query!.isEmpty {
            ...
            self.delegate?.reassureShowingList()
            ...
        }
        ...
    }
    

    And in the controller contains the SearchController, we add our delegate:

    self.searchResultsController.delegate = self
    func reassureShowingList() {
        searchController.searchResultsController!.view.hidden = false
    }
    
    0 讨论(0)
  • 2020-12-23 13:33

    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.

    0 讨论(0)
  • 2020-12-23 13:37

    I really liked Simon Wang's answer and worked with it and this is what I did and it works perfectly:

    I subclass the UISearchController in my custom class:

    class CustomClass: UISearchController {
      override var searchResultsController: UIViewController? {
        get {
          let viewController = super.searchResultsController
          viewController?.view.isHidden = false
          return viewController
        }
        set {
          // nothing
        }
      }
    }
    

    Also make sure you don't have this anywhere in your code:

    self.resultsSearchController.isActive = true
    

    resultsSearchController is my UISearchController

    0 讨论(0)
  • 2020-12-23 13:40

    Swift 4 version of malhals answer:

    class SearchController: UISearchController {
    
        private var viewIsHiddenObserver: NSKeyValueObservation?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            viewIsHiddenObserver = self.searchResultsController?.view.observe(\.hidden, changeHandler: { [weak self] (view, _) in
                guard let searchController = self else {return}
                if view.isHidden && searchController.searchBar.isFirstResponder {
                view.isHidden = false
                }
            })
    
        }
    
    }
    

    Please note the [weak self]. Otherwise you would introduce a retain cycle.

    0 讨论(0)
  • 2020-12-23 13:41

    What is being hidden is the search results controller's view. Therefore it is sufficient to unhide it any time it might be hidden. Simply do as follows in the search results controller:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.view.isHidden = false
    }
    
    func updateSearchResults(for searchController: UISearchController) {
        self.view.isHidden = false
        // ... your other code goes here ...
    }
    

    Now the results view (i.e. the table view) is always visible, even when the search bar text is empty.

    By the way, the iOS Mail app behaves like this, and I assume that's how it's implemented (unless Apple has access to some secret private UISearchController setting).

    [Tested in iOS 10 and iOS 11; I didn't test on any earlier system.]

    0 讨论(0)
提交回复
热议问题