Показать предварительно загруженные результаты поиска?

У меня есть представление без табличного представления с панелью поиска в нем, и хотя оно отлично работает, контроллер отображения поиска скрывает табличное представление и накладывает темный затемненный вид, когда на панели поиска находится пустая строка. Я хочу, чтобы он показывал предварительно загруженные данные, когда пустая строка находится на панели поиска, вместо того, чтобы скрывать представление таблицы и накладывать темное затемненное представление под панелью поиска. Точно так же, как работает панель поиска Google в Safari для iOS.

Я встречал аналогичный вопрос, заданный ранее в stackoverflow: UISearchDisplayController - как предварительно загрузить searchResultTableView, I не мог заставить его работать.

У меня нет проблем с получением предварительно загруженных данных и установкой для них текущих данных, но я не знаю, как предотвратить удаление searchResultsTableView контроллером дисплея.

Заранее спасибо.


person Dennis    schedule 24.05.2012    source источник


Ответы (7)


Я наконец нашел способ сделать это.

Я обнаружил, что searchDisplayController просто удаляет searchResultsTableView из супервизора, поэтому я просто добавил табличное представление обратно в супервизор всякий раз, когда контроллер дисплея пытался скрыть табличное представление:

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
    // add the tableview back in
    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
}

а затем мне также нужно показать табличное представление при первом щелчке панели поиска, поэтому я сделал:

- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
    // after the data has been preloaded
    self.searchResults = self.allItems;
    [self.searchDisplayController.searchResultsTableView reloadData];
}

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
{
    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
}

Для меня allItems - это место, где я хранил все доступные для поиска элементы, а searchResults - это место, где хранятся отфильтрованные элементы (после поиска). И, конечно же, вам нужно будет предварительно загрузить элементы (например, историю поиска) перед перезагрузкой данных.

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

person Dennis    schedule 28.05.2012
comment
Пытаюсь понять это уже несколько дней! Спасибо за решение! - person Anil Natha; 07.02.2013
comment
После тестирования этой реализации я теперь хочу выяснить, как сделать так, чтобы контейнер результатов поиска не мерцал при добавлении в представление. Поскольку он добавляется с помощью метода searchDisplayControllerDidBeginSearch:, вы можете увидеть тусклый фон на долю секунды до того, как отобразится searchResultsTableView. Есть мысли о том, как это обойти? Я попытался переместить строку кода из searchDisplayControllerDidBeginSearch в searchDisplayControllerWillBeginSearch' method, but that causes the dim background to be placed in front of the searchResultsTableView` - person Anil Natha; 07.02.2013
comment
Это больше не работает на iOS 7. У кого-нибудь есть рабочее решение? - person OpenUserX03; 12.10.2013
comment
Да, это не работает в iOS 8. У кого-нибудь есть решение? - person coolcool1994; 28.05.2016

Спустя несколько часов я наконец нашел решение, которое работает в iOS 7.

Просто реализуйте следующие два метода в своем UISearchDisplayDelegate

-(void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {

    // We need to prevent the resultsTable from hiding if the search is still active
    if (self.searchDisplayController.active == YES) {
        tableView.hidden = NO;
    }
}

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

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {

    controller.searchResultsTableView.hidden = NO;

    // Then we need to remove the semi transparent overlay which is here
    for (UIView *v in [[[controller.searchResultsTableView superview] superview] subviews]) {

        if (v.frame.origin.y == 64) {
            [v setHidden:YES];
        }
    }

}
person Joseph Williamson    schedule 16.02.2014
comment
У меня это не сработало на iOS7. Вместо этого я проверил, кажется ли (v.alpha ‹1) наиболее устойчивым хаком. - person Daniel Larsson; 13.05.2014

Я нашел гораздо лучшее решение этой проблемы, и, похоже, оно отлично работает на iOS 6 и 7. Хотя это все еще хак, это гораздо более чистый и перспективный хак, чем описанный выше. Другие решения работают нестабильно и предотвращают запуск некоторых методов UISearchDisplayDelegate! Кроме того, у меня были сложные проблемы со вставкой, которые я не мог решить с помощью вышеуказанных методов. Основная проблема с другими решениями заключается в том, что они серьезно сбивают с толку внутреннее устройство UISearchDisplayController. Мое решение основано на наблюдении, что UISearchDisplayContoller является UISearchbarDelegate и что автоматическое снятие яркости и отображение таблицы результатов может быть запущено путем имитации нажатия клавиши в поле поиска! Так:

- (void) searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller 
{
    if ([controller respondsToSelector: @selector(searchBar:textDidChange:)])
        [(id<UISearchBarDelegate>)controller searchBar: controller.searchBar textDidChange: @" "];
}

Этот код является будущим средством защиты от сбоев, проверяя, что он отвечает на метод UISearchbarDelegate и отправляет пробел @ "", чтобы обмануть UISearchDisplayController, заставив его думать, что пользователь ввел букву.

Теперь, если пользователь что-то набирает, а затем стирает, таблица снова тускнеет. Другие решения пытаются обойти это, делая что-то в методе searchDisplayController: didHideSearchResultsTableView :. Но для меня это не имеет смысла, поскольку, конечно, когда вы отмените поиск, вам нужно будет действительно скрыть вашу таблицу результатов, и в этом случае вам может потребоваться запустить код. Мое решение для этой части - создать подкласс (обратите внимание, что вы, вероятно, могли бы использовать категорию Method Swizzled, чтобы она работала везде, если это необходимо в вашем проекте):

// privately declare protocol to suppress compiler warning
@interface UISearchDisplayController (Super) <UISearchBarDelegate>
@end

// subclass to change behavior
@interface GMSearchDisplayController : UISearchDisplayController
@end

@implementation GMSearchDisplayController

- (void) searchBar: (UISearchBar *) searchBar textDidChange: (NSString *) searchString
{
    if (searchString.length == 0)
        searchString = @" ";
    if ([super respondsToSelector: @selector(searchBar:textDidChange:)])
        [super searchBar: searchBar textDidChange: searchString];
}

@end

Этот код работает, перехватывая метод делегата textDidChange и заменяя пустые или пустые строки на пробел string @ "", предотвращая обычное скрытие / затемнение, которое происходит на пустой панели поиска. Если вы используете этот второй бит кода, то вы можете изменить первый бит так, чтобы он передавал ноль вместо @ "", поскольку этот второй бит выполнит необходимое преобразование в @ "" за вас.

В моем собственном проекте мне нужно было обработать случай, когда пользователь вводит пробел, поэтому вместо @ "" выше я использовал определенный токен:

// arbitrary token used internally
#define SEARCH_PRELOAD_CONDITIONAL @"_#preresults#_"

А затем обработайте его внутренне, преобразовав обратно в нулевую строку:

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    if ([searchString isEqualToString: SEARCH_PRELOAD_CONDITIONAL])
        searchString = nil;
}

Наслаждаться! :)

person stonemonk    schedule 17.07.2014

Это работает в iOS 8:

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
  self.searchDisplayController.searchResultsTableView.hidden = NO;
}

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
{
    self.searchDisplayController.searchResultsTableView.hidden = NO;
    [self.searchDisplayController.searchResultsTableView.superview.superview bringSubviewToFront:self.searchDisplayController.searchResultsTableView.superview];

    CGRect frame = self.searchDisplayController.searchResultsTableView.frame;
    self.searchDisplayController.searchResultsTableView.frame = CGRectMake(frame.origin.x, 64, frame.size.width, frame.size.height);
}
person Marcio Fonseca    schedule 07.01.2015

Когда вы начинаете поиск, вызывается этот метод. Добавьте searchResultsTableView и покажите его. Затем он отобразит ваши уже предварительно загруженные данные. Чтобы это сработало, мне необходимо предварительно загрузить ваши данные.

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller
{
    CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height);
    self.searchDisplayController.searchResultsTableView.frame = testFrame;
    [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];

//    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
    controller.searchResultsTableView.hidden = NO;
}

-(void) searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView
{
    CGRect testFrame = CGRectMake(0, self.notesSearchBar.frame.size.height, self.notesSearchBar.frame.size.width, self.view.frame.size.height - self.notesSearchBar.frame.size.height);
    self.searchDisplayController.searchResultsTableView.frame = testFrame;
    [self.notesSearchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];

    //    [self.view addSubview:self.searchDisplayController.searchResultsTableView];
    controller.searchResultsTableView.hidden = NO;
}


-(void) searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
    controller.searchResultsTableView.hidden = YES;
}
person coolcool1994    schedule 30.10.2013

Рабочий код iOS 9.

- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
    // Bring the search table view to the view's front
    self.searchDisplayController.searchResultsTableView.hidden = NO;
    [self.searchDisplayController.searchResultsTableView.superview bringSubviewToFront:self.searchDisplayController.searchResultsTableView];
}

- (void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {
    // We need to prevent the resultsTable from hiding if the search is still active
    if (self.searchDisplayController.active == YES) {
        tableView.hidden = NO;
    }
}
person Pedro Góes    schedule 07.01.2016

Версия Swift 2.0+

func searchDisplayControllerDidBeginSearch(controller: UISearchDisplayController) {
    controller.searchResultsTableView.hidden = false
    controller.searchResultsTableView.superview!.bringSubviewToFront(controller.searchResultsTableView)
}

func searchDisplayController(controller: UISearchDisplayController, didHideSearchResultsTableView tableView: UITableView) {
    if ((searchDisplayController?.active) != nil) {
        tableView.hidden = false
    }
}
person Aluminum    schedule 09.03.2016