UISearchDisplayController - как предварительно загрузить searchResultTableView
Я хочу показать некоторый контент по умолчанию, когда пользователь удаляет панель поиска, но до ввода любого текста.
У меня есть решение, использующее settext:
- (void) searchDisplayControllerDidBeginSearch:(UISearchDisplayController *)controller {
[searchDisplayController.searchBar setText:@" "];
}
Это работает, но это не изящно, и текст подсказки в панели поиска исчезает.
Есть ли лучший способ предварительной загрузки данных в SearchResultTableView в UISearchDisplayController, без необходимости реализовать всю функциональность UISearch самостоятельно в пользовательском контроллере?
Для демонстрации желаемого эффекта просмотрите окно поиска Safari, если вы нажмете его, откроется интерфейс поиска с предыдущими показаниями.
Ответы
Ответ 1
Хорошо, у меня оно есть. Предварительно загрузите 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, et voila.
Я подтвердил, что это правильно, показывая супервизор searchBar и супервизор tableView после правильной загрузки tableView - они имеют одинаковый супервизор. Итак, я вернусь и добавлю tableView в супервизор на раннем этапе, и, конечно же, он появится. Для меня это показалось тусклым (может быть, еще один вид выше? Alpha set lower?), Но он по-прежнему доступен для клика. Я не пошел дальше, но это определенно дает вам отображение tableView без какого-либо взаимодействия с пользователем.
Enjoy,
Damien
Ответ 2
Я нашел решение гораздо лучше для этой проблемы, и, похоже, он отлично работает на 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, и отправляет space @"", чтобы обмануть 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#_"
И затем обработайте его внутренне, переведя его обратно в строку nil:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
if ([searchString isEqualToString: SEARCH_PRELOAD_CONDITIONAL])
searchString = nil;
}
Наслаждайтесь!:)
Ответ 3
Рабочее решение для 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;
}
}
Ответ 4
У меня есть решение. Вставьте эти три метода. Для работы с таблицей необходимо предварительно загрузить данные. У меня эти коды работают в моем коде, поэтому он должен работать для вас, если вы уже предварительно загрузили данные, и вы используете контроллер отображения поиска.
- (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;
}
Ответ 5
Это работает в 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).
Ответ 6
Я тестировал следующее в iOS 9 с UISearchController.
По умолчанию, всякий раз, когда в UISearchBar нет текста, приведенная таблица будет вашим исходным представлением таблицы (называемым originalTableView). Это может иметь или не иметь черный прозрачный слой в зависимости от значения dimsBackgroundDuringPresentation
.
Как только пользователь вводит какой-либо текст в UISearchBar, будет отображаться содержимое нового представления таблицы (я буду называть это как searchTableView).
Обратите внимание, что в обоих этих решениях я реализую UISearchController аналогично тому, как Apple делает это в в этом примере; а именно, есть два отдельных UITableViewController, отвечающих за отображение данных.
Решение 1: Сложная реализация, более плавная анимация
Для более плавной анимации:
- Внедрение методов UISearchControllerDelegate willPresentSearchController и willDismissSearchController.
- В willPresent обновите исходные данные TableView, чтобы подготовиться к отображению нужных нужных текстовых данных, а затем вызвать
reloadData()
.
- В willDismiss верните процесс, чтобы показать исходное содержимое, и вызовите
reloadData()
.
Пример:
// 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: Быстрая реализация, изменчивая анимация
Вместо того, чтобы реализовывать логику для контроллера поиска как в исходномTableView, так и в 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()
}
}
Ответ 7
Почему бы вам не взглянуть на проект TableSearch, который входит в Xcode? Он более или менее адресует то, что вам нужно. Он показывает таблицу в начале и оттеняет ее, когда поле поиска используется. Проверьте таблицу поиска в документации и ссылке на API в Xcode 4 под справкой.
Также взгляните на this Это почти то, что вам нужно с UISearchBar и UITableView. Вместо этого я предпочел бы этот подход. Измените его.
И для дальнейшего удовлетворения ваших потребностей я бы предложил использовать два источника данных. Один из них содержит все содержимое (это то, что вы покажете в самом начале), и один для хранения отфильтрованных результатов поиска. Теперь идите и очистите первый источник данных и заполните его содержимым второго, чтобы сохранить и снизьте результаты предыдущего поиска. Действуйте так. Используйте этот подход в коде TableSearch для своей задачи.
Ответ 8
Здесь можно предварительно заполнить 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;
}
//Надеюсь, это поможет.
Спасибо