UISearchDisplayController - как предварительно загрузить searchResultTableView - PullRequest
27 голосов
/ 03 июня 2011

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

У меня есть решение, работающее с использованием settext:

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

   [searchDisplayController.searchBar setText:@" "];

}

Это работает, ноэто не элегантно, и текст подсказки на панели поиска исчезает.

Есть ли лучший способ предварительно загрузить данные в SearchResultTableView в UISearchDisplayController, без необходимости реализовывать всю функциональность UISearch самостоятельно в пользовательском контроллере?

Для демонстрации желаемого эффекта, посмотрите на окно поиска Safari, если вы нажмете на него, откроется интерфейс поиска с предыдущими поисками, показывающими.

Ответы [ 8 ]

9 голосов
/ 01 марта 2012

ОК, у меня это есть.Предварительно загрузите ваш dataSource с некоторыми данными и сделайте следующий хак (ничего противозаконного), и вы увидите tableView, который будет отображаться.Обратите внимание, что может потребоваться некоторая очистка, но это приведет к отображению данных по умолчанию.

В viewDidLoad контроллера представления, который владеет UISearchBar:

[super viewDidLoad];
[self.searchDisplayController.searchResultsTableView reloadData];
// whatever you named your search bar - mine is property named searchBar
CGRect testFrame = CGRectMake(0, 20, self.searchBar.frame.size.width, 100);
self.searchDisplayController.searchResultsTableView.frame = testFrame;
[self.searchBar.superview addSubview:self.searchDisplayController.searchResultsTableView];

Вот чтопроисходит:
UISearchBar не хочет показывать searchResultsTableView, пока вы не начнете редактирование.Если вы дотронетесь до tableView (например, reloadData), он загрузится и будет там, сидя в памяти с frame = CGRectZero.Вы даете ему правильный кадр, а затем добавляете его в суперпредставление searchBar и так далее.

Я подтвердил, что это правильно, отобразив суперпредставление searchBar и суперпредставление tableView после правильная загрузка tableView - они имеют один и тот же супервизор.Итак, я возвращаюсь и добавляю tableView к суперпредставлению на ранней стадии, и, конечно же, он появляется.Для меня это показалось затемненным (может быть, другой вид над ним - альфа установлен ниже?), Но все равно было кликабельным.Я не пошел дальше, но это определенно дает вам отображение вашего tableView без какого-либо взаимодействия с пользователем.

Наслаждайтесь,

Damien

8 голосов
/ 17 июля 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: метод.Но это не имеет смысла для меня, так как, конечно, когда вы отменяете поиск, ему нужно будет действительно скрыть таблицу результатов, и вам может потребоваться запустить код в этом случае.Мое решение для этой части - создать подкласс (обратите внимание, что вы, вероятно, могли бы использовать метод Swizzled Category, чтобы он работал везде, где это необходимо в вашем проекте):

// 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 и измененияноль или пустые строки в пробел @ "" предотвращают нормальное скрытие / затемнение, которое происходит на пустой панели поиска.Если вы используете этот второй бит кода, то вы можете изменить первый бит, чтобы передать ноль вместо @ "", так как этот второй бит сделает необходимое преобразование в @ "" для вас.

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

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

И затем обработал его внутренне, преобразовав его обратно в ноль-строку:

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

Наслаждайтесь!:)

4 голосов
/ 13 мая 2014

Рабочее решение для iOS 7:

// When the tableView is hidden, put it back
- (void)searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
    [self.searchDisplayController.searchResultsTableView reloadData];
    controller.searchResultsTableView.hidden = NO;

    // Also, remove the dark overlay
    for (UIView *v in [[controller.searchResultsTableView superview] subviews]) {
        // This is somewhat hacky..
        if (v.alpha < 1) {
            [v setHidden:YES];
        }
    }
}

-(void)searchDisplayController:(UISearchDisplayController *)controller didHideSearchResultsTableView:(UITableView *)tableView {
    [self.searchDisplayController.searchResultsTableView reloadData];
    if (self.searchDisplayController.active == YES) {
        tableView.hidden = NO;
    }
}
1 голос
/ 06 июля 2015

Я протестировал следующее в iOS 9 с UISearchController.

По умолчанию, когда в UISearchBar нет текста, показанная таблица будет вашим исходным табличным представлением (далее именуемым originalTableView ). Это может иметь или не иметь черный прозрачный слой в зависимости от значения dimsBackgroundDuringPresentation.

Как только пользователь вводит любой текст в UISearchBar, будет отображаться содержимое нового табличного представления (я буду называть это searchTableView ).

Обратите внимание, что в обоих этих решениях я реализую UISearchController способом, аналогичным тому, как это делает Apple в в этом примере ; а именно, есть два отдельных UITableViewController, отвечающих за отображение данных.

Решение 1. Сложная реализация, более плавная анимация

Для более плавной анимации:

  1. Реализация методов willPresentSearchController и willDismissSearchController для UISearchControllerDelegate.
  2. В willPresent обновите данные вашего оригинального TableView, чтобы подготовиться к отображению любых нулевых текстовых данных, которые вам нужны, затем наберите reloadData().
  3. В willDismiss верните процесс, чтобы показать исходное содержимое, и наберите reloadData().

Пример: * 1 034 *

// here tableView refers to originalTableView

extension ViewController: UISearchControllerDelegate {
    func willPresentSearchController(searchController: UISearchController) {
        data = ["A", "B", "C"]
        tableView.reloadData()
    }

    func willDismissSearchController(searchController: UISearchController) {
        data = ["a", "b", "c"]
        tableView.reloadData()
    }
}

В этом вымышленном примере данные отображаются как a,b,c, когда пользователь не фокусируется на UISearchBar, а отображаются как A,B,C, когда пользователь нажимает на UISearchBar.

Решение 2: Быстрая реализация, прерывистая анимация

Вместо реализации логики для контроллера поиска как в originalTableView, так и в searchTableView, вы можете использовать это решение, чтобы просто показать searchTableView, даже если он по умолчанию скрыт.

Скорее всего, вы уже внедрили протокол UISearchResultsUpdating. Просто вызвав tableView.hidden = false в этом методе, вы должны получить поведение, за которым следите; хотя и с менее звездной анимацией.

// here tableView refers to searchTableView

extension SearchViewController: UISearchResultsUpdating {
    func updateSearchResultsForSearchController(searchController: UISearchController) {
        tableView.hidden = false
        filterData(text: searchController.searchBar.text!)
        tableView.reloadData()
    }
}
1 голос
/ 07 января 2015

Это работает в 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);
}

Однако мне не понравился этот взлом, и я заменил searchDisplayController собственной реализацией (UISearchBar с UITableView).

1 голос
/ 30 октября 2013

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

- (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;
}
0 голосов
/ 01 марта 2012

Вот способ предварительно заполнить searchController.

// 1. Сохранить предыдущие результаты поиска, как только пользователь введет текст

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    // save searchString

    return YES;
}

// 2. загрузить предыдущую строку поискапри запуске

- (void)viewDidLoad 
{
    // create data source for table view
    // searchData may be a NSMutableArray property defined in your interface

    self.searchData = // search your master list for searchString

    // or create your own list using any search criteria you want

    // or you may act depending on user preference
    if(!showPreviousSearch)
    {
        // [searchData removeAllObjects];
    }
}

// 3. предоставить правильный источник данных при запросе

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
    {
        ...
    }

    NSMutableArray *dataSource = nil;
    if (tableView == [[self searchDisplayController] searchResultsTableView])
    {
        dataSource = self.searchData;
    }
    else
    {
        dataSource = self.masterData;
    }

    ...

    return cell;
}

// Надеюсь, это поможет.

0 голосов
/ 28 сентября 2011

Почему бы вам не взглянуть на проект TableSearch, который поставляется в Xcode? Это более или менее адрес того, что вам нужно. Она показывает таблицу в самом начале и затеняет ее, когда коснитесь поля поиска. Проверьте TableSearch в Документации и ссылку API в Xcode 4 под справкой.

Также взгляните на this Он почти делает то, что вам нужно с UISearchBar и UITableView. Я бы предпочел такой подход. Настройте его.

И для дальнейшего удовлетворения ваших потребностей я бы предложил использовать два источника данных. Один содержит все содержимое (это то, что вы бы показали в самом начале), а второй - отфильтрованные результаты поиска. Теперь очистите первый источник данных и заполните его содержимым второго, чтобы сохранить и затемнить результаты предыдущего поиска. Продолжайте в том же духе. Используйте этот подход в коде TableSearch для своей задачи.

...