2015-06-11 4 views
27

Как я понимаю, поведение по умолчанию UISearchController является:UISearchController: показать результаты, даже если строка поиска пуста

  1. На коснувшись панели поиска, фон серый цвет и «отмена» кнопка отображается. SearchResultsController не показан до этого момента.
  2. SearchResultsController отображается, только если строка поиска не пуста.

Я хочу отображать SearchResultsController, даже если панель поиска пуста, но выбрана (например, пример 1 выше).

Проще говоря, вместо подсветки фона, я хотел бы показать результаты поиска.

Есть ли способ для этого?

Больше Разъяснение:

Я не использую UISearchController фильтровать результаты, показанные на представлении, на котором он показан, но и некоторые другие, не связанные результаты. Это будет похоже на то, что делает facebook на своей «Лента новостей». Нажатие на панель поиска сначала показывает поисковые предложения, а затем, когда мы начинаем редактирование, оно показывает результаты поиска, которые могут быть не связаны с лентой новостей.

ответ

24

Если ваш поискБар активен, но не имеет текста, отображаются результаты таблицы tableView. Это встроенное поведение и причина, по которой searchResultsController скрыт для этого состояния.

Чтобы изменить поведение, когда поиск активен, но не фильтрует, вам нужно будет показать searchResultsController, когда он обычно скрыт.

Возможно, это может быть сделано с помощью <UISearchResultsUpdating> и updateSearchResultsForSearchController:. Если вы можете решить это по протоколу, это предпочтительный способ.

Если это не помогает, вы можете взломать встроенное поведение.Я бы не рекомендовал или полагаться на него, и он будет хрупким, но вот ответ, если вы выбрали этот вариант:

  1. Убедитесь, что ваш tableViewController соответствует <UISearchControllerDelegate>, и добавить

    self.searchController.delegate = self;

  2. Реализовать willPresentSearchController:

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

    Это делает searchResultsController, видимый после UISearchController, должен быть скрыт.

  3. Реализовать didPresentSearchController:

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

Для лучшего способа обойти встроенный в поведении см malhal's answer.

+0

Спасибо! Я попробовал взломать, и это сработало. Один вопрос, для чего «dispatch_async»? – optimus

+0

Dispatch_async рассылает метод, который будет вызываться в следующем цикле запуска. По сути, он добавляет небольшую задержку к вызываемому методу, поэтому мы можем отобразить 'searchResultsController' * после того, как * контроллер поиска пометил его скрытым. –

+0

Очень редко экран мерцает от тусклого до вида. Но работы, спас мне много боли. – tGilani

0

Я думаю, вы ошибаетесь.

SearchResultsController появляется только при наличии результатов. Это немного отличается от вашей интерпретации.

Результаты загружаются вручную на основе текста в строке поиска. Поэтому вы можете перехватить его, если панель поиска пуста и вернуть свой собственный набор результатов.

+0

У меня всегда есть результаты (даже для пустой панели поиска). Где я должен перехватить и «вернуть» его? установка свойства 'active' на YES в 'searchBarTextDidBeginEditing' не работает. – optimus

+0

В поезде на данный момент так не удается найти имена методов. Какой код вы используете для возврата результатов? – Fogmeister

+0

Я никуда не возвращаю результаты. Мой SearchResultsController - это отдельный контроллер представлений, в котором результаты задаются в методе 'updateSearchResultsForSearchController'. Метод вызывается UISearchController, когда текст в строке поиска изменяется или «активный» установлен на «да». Это нормально работает, когда у меня есть текст в строке поиска. – optimus

0

Если вы не хотите уменьшать результаты, установите dimsBackgroundDuringPresentation на false.

Это гарантирует, что основной контент не будет затемнен во время поиска.

Вам также необходимо убедиться, что вы возвращаете результаты, даже если searchText пуст, иначе будет отображаться пустой столбец.

+0

Dimming не моя забота, не показывая результаты контроллер. Пожалуйста, уточните, что я добавил. – optimus

12

Я испробовал решение PetahChristian, результат предварительной загрузки действительно появился, когда мы впервые сфокусировали поисковую панель, но когда мы вводим что-то, то очищаем его, результаты предварительной загрузки снова не появятся.

Я придумал другое решение. Нам нужно добавить делегата в SearchResultsController и вызвать его, когда наш searchController.searchBar.text пуст. Что-то вроде этого:

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() 
     ... 
    } 
    ... 
} 

И в контроллере содержит SearchController, мы добавим наш делегат:

self.searchResultsController.delegate = self 
func reassureShowingList() { 
    searchController.searchResultsController!.view.hidden = false 
} 
+0

Отличное решение! Я также должен был вызвать unhiding searchResultsController в основном потоке, а затем отлично работает. – rafalkitta

+1

Лично я считаю, что это должно быть принято как ответ! Он работает без проблем! –

+0

Абсолютно. Простой и автономный. –

11

С хитрыми вещами, как это я рекомендую молот подход саней! То есть, чтобы обнаружить, когда что-то пытается скрыть его, и когда это произойдет, измените его. Это можно сделать с помощью KVO (Key Value Observing). Это будет работать независимо от того, что, без необходимости обрабатывать все тонкости панели поиска. Извините, код сложный, но KVO - это старый API, но мой код следует рекомендациям. В вашем SearchResultsViewController поставить это:

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 

Это работает во всех случаях, в том числе, если текст будет очищен.

Наконец, чтобы предотвратить таблицу делать некрасивый увядает к серому затем белым, когда поиск активирует, используйте:

self.searchController.dimsBackgroundDuringPresentation = NO; 
+0

Для менее подробной версии того же, см. Мой ответ. – skensell

24

Вы можете просто реализовать протокол UISearchResultsUpdating и установить вид контроллера результаты всегда показывать в updateSearchResultsForSearchController:

func updateSearchResultsForSearchController(searchController: UISearchController) { 

    // Always show the search result controller 
    searchController.searchResultsController?.view.hidden = false 

    // Update your search results data and reload data 
    .. 
} 

Это работает, потому что метод вызывается, даже когда панель поиска активируется, без какого-либо текста.

+2

Это сработало для меня, и это намного проще, чем другие предлагаемые методы. –

0

Я потратил много времени на это, и в конечном итоге решение, с которым я побывал, похоже на @ malhals, но количество кода значительно уменьшено с помощью KVOController от facebook: https://github.com/facebook/KVOController.Другое преимущество здесь в том, что если ваш searchResultsController является UINavigationController, вам не нужно подклассифицировать его только для добавления кода @ malhal.

// always show searchResultsController, even if text is empty 
[self.KVOController observe:self.searchController.searchResultsController.view keyPath:@"hidden" options:NSKeyValueObservingOptionNew block:^(id observer, UIView* view, NSDictionary *change) { 
    if ([change[NSKeyValueChangeNewKey] boolValue] == YES) { 
     view.hidden = NO; 
    } 
}]; 
self.searchController.dimsBackgroundDuringPresentation = NO; 
+0

Блоки с крахом KVO и похожими на библиотеки Facebook имеют те же проблемы – malhal

+0

В библиотеке Facebook есть только одна открытая проблема, и это когда вы наблюдаете себя как '[self.KVOController наблюдать: self keypath: ...'. Я использую вышеуказанный код, и нет цикла сохранения и сбоя. – skensell

+0

Проблема связана с dealloc и несколькими экземплярами контроллера вида. Если наблюдатель не будет удален правильно, он сработает.Возможно, попробуйте этот, так как он правильно использует dealloc: https://github.com/jpmhouston/TotalObserver – malhal

3

версия Swift 2.3 @ malhal Подход:

class SearchResultsViewController : UIViewController { 
    var context = 0 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Add observer 
     view.addObserver(self, forKeyPath: "hidden", options: [ .New, .Old ], context: &context) 
    } 

    deinit { 
     view.removeObserver(self, forKeyPath: "hidden") 
    } 

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) { 
     if context == &self.context { 
      if change?[NSKeyValueChangeNewKey] as? Bool == true { 
       view.hidden = false 
      } 
     } else { 
      super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) 
     } 
    } 
} 
5

Swift 3 Версия:

Если searchResultController не ноль, и вы используете отдельный контроллер представления таблицы, чтобы отобразить результаты поиска, то вы можете сделать это табличное контроллер соответствует UISearchResultUpdating и в функции updateSearchResults, вы можете просто отобразить вид.

func updateSearchResults(for searchController: UISearchController) { 
    view.hidden = false 
} 
1

Я недавно работал над UISearchController. Я хочу показать историю поиска в searchResultsController, когда панель поиска пуста. Поэтому searchResultsController должен отображаться при представлении UISearchController.

Я не совсем удовлетворен решениями, которые переворачивают скрытый флаг, установленный UISearchController (встроенное поведение). Я попробовал другое решение, чтобы сделать searchResultsController всегда видимым , переопределяя скрытое свойство в пользовательском представлении.

например, мой поискРезультатыКонтроллер - это UITableViewController. Я создаю VisibleTableView в качестве подкласса UITableView, а затем изменяю пользовательский класс поиска UITableView searchResultsController на VisibleTableView в xib или раскадровке. Таким образом, мой поискResultsController никогда не будет скрыт UISearchController.

Хорошие вещи здесь:

  1. легче реализовать, чем КВО.

  2. Отсутствие задержки для поиска searchResultsController. Перемещение скрытого флага в метод делегирования «updateSearchResults» работает, но есть задержка, чтобы показать searchResultsController.

  3. Он не перезагружает скрытый флаг, поэтому нет разрыва между UI и между скрытым и видимым.

Swift код 3 образца:

class VisibleTableView: UITableView { 
override var isHidden: Bool { 
    get { 
     return false 
    } 
    set { 
     // ignoring any settings 
    } 
} 
} 
+0

Это, безусловно, лучшее решение! – plu

2

Что прячась вид контроллера Результаты поиска по. Поэтому достаточно отобразить его в любое время, когда оно может быть скрыто. Просто выполните следующие действия в контроллере результатов поиска:

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 ... 
} 

Теперь вид результатов (то есть вид таблицы) всегда виден, даже если текст строки поиска пуст.

Кстати, приложение iOS Mail ведет себя так, и я предполагаю, что так оно реализовано (если у Apple нет доступа к секретной частной настройке UISearchController).

[Испытано в iOS 10 и iOS 11; Я не проверял на более раннюю систему]

+0

Я знаю, что этот комментарий бесполезен, но этот ответ недооценен – sasquatch

0

Мне очень понравился ответ Саймон Ван и работал с ним, и это то, что я сделал, и он прекрасно работает:.

I подкласс UISearchController в моем пользовательском классе:

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

Также убедитесь, что вы не имеете это где-нибудь в вашем коде:

self.resultsSearchController.isActive = true 

resultsSearchController мой UISearchController

0

Swift версия 4 из 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 
      } 
     }) 

    } 

} 

Пожалуйста, обратите внимание, что [weak self]. В противном случае вы вводите цикл удержания.

Смежные вопросы