Кнопка кнопки раскрытия информации UITableViewCell слишком далеко справа во время поиска
У меня UITableViewController
с UISearchBar
как tableHeaderView
его tableView
. У меня также есть UISearchDisplayController
, инициализированный тем, что UISearchBar
как его searchBar
, и UITableViewController
как его contentsController
. Пока все хорошо, все почти работает.
Проблема в том, что UITableView
имеет ячейки, у которых их accessoryType
установлен на UITableViewCellAccessoryDetailDisclosureButton
. Вот что происходит:
- Чтобы начать, все выглядит так, как должно:
![enter image description here]()
- Пользователь забирает внутри
UISearchBar
.
-
UISearchDisplayController
создает темную надпись поверх основной таблицы и уменьшает индекс (как в sectionIndexTitlesForTableView
) основной таблицы.
- Предположим, что пользователь в этот момент скрывает клавиатуру (нажав кнопку "Скрыть клавиатуру iPad" на стандартной клавиатуре)
- Так как пользователь еще ничего не набрал в
UISearchBar
, мы все равно можем видеть основную таблицу, хотя и под темным наложением, добавленным UISearchDisplayController
.
- Скрытие клавиатуры предоставляет большую часть основной таблицы, заставляя основную таблицу загружать больше ячеек.
- Теперь вот проблема: Так как эти ячейки загружаются, когда указатель главной таблицы скрыт, кнопка раскрытия отображается слишком далеко справа (по крайней мере, по сравнению с другими ячейками).
![enter image description here]()
- Кроме того, когда пользователь отменяет поиск, эти ячейки не могут быть перезагружены, что приведет к тому, что кнопка раскрытия будет показана под индексом (который теперь снова отображается).
![enter image description here]()
Я не понимаю, как обойти это; единственный вариант, о котором я могу думать, - найти UIView, который соответствует кнопке раскрытия и вручную переместить его, но это кажется невероятно взломанным, хотя бы потому, что даже если найти UIView требует неприятного взлома. Любые предложения о том, как исправить это лучше, будут очень благодарны!
Минимальный пример runnable
Ниже приведен минимальный пример. Просто запустите новый проект XCode, включите только ARC, iPad и замените содержимое AppDelegate ниже. Обратите внимание, что для минимального примера я заставляю основную таблицу перезагружать свои ячейки в searchDisplayController:willShowSearchResultsTableView
, в противном случае основная таблица будет кэшировать его ячейки, и проблема не будет отображаться (в моем фактическом приложении основная таблица перезагружает свои ячейки по другим причинам, я не совсем уверен, почему, но, конечно, должно быть хорошо, если основная таблица будет перезагружать ячейки в любое время.)
Чтобы увидеть проблему, запустите код, введите что-то в поле поиска (вы увидите "Результат поиска 0.. 5" ), а затем отмените поиск. Кнопки раскрытия основной таблицы теперь отображаются ниже, а не рядом с индексом.
Ниже приведен только код:
@interface AppDelegate ()
@property (nonatomic, strong) UITableViewController* mainTableController;
@property (nonatomic, strong) UISearchDisplayController* searchDisplay;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UITableViewController* tableViewController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
UITableView* tableView = [tableViewController tableView];
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
[tableView setDataSource:self];
[self setMainTableController:tableViewController];
UISearchBar* searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 0, 44)]; // Width set automatically
[tableView setTableHeaderView:searchBar];
UISearchDisplayController* searchDisplay = [[UISearchDisplayController alloc] initWithSearchBar:searchBar
contentsController:tableViewController];
[searchDisplay setSearchResultsDataSource:self];
[searchDisplay setDelegate:self];
[self setSearchDisplay:searchDisplay];
[[self window] setRootViewController:tableViewController];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (tableView != [[self searchDisplay] searchResultsTableView]) {
return 26;
} else {
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView != [[self searchDisplay] searchResultsTableView]) {
return 10;
} else {
return 5;
}
}
- (void)searchDisplayController:(UISearchDisplayController *)controller willShowSearchResultsTableView:(UITableView *)tableView {
// The problem arises only if the main table view needs to reload its data
// In this minimal example, we force this to happen
[[[self mainTableController] tableView] reloadData];
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"SearchCell"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView != [[self searchDisplay] searchResultsTableView]) {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
[[cell textLabel] setText:[NSString stringWithFormat:@"%c%d", 'A' + [indexPath section], [indexPath row]]];
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
return cell;
} else {
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"SearchCell" forIndexPath:indexPath];
[[cell textLabel] setText:[NSString stringWithFormat:@"Search result %d", [indexPath row]]];
[cell setAccessoryType:UITableViewCellAccessoryDetailDisclosureButton];
return cell;
}
}
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
if (tableView != [[self searchDisplay] searchResultsTableView]) {
return [NSArray arrayWithObjects:@"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z", nil];
} else {
return nil;
}
}
Ответы
Ответ 1
Если вы хотите подражать тому, как, по-видимому, ведут себя собственные приложения Apple, в этом случае правильный ход действий станет причиной того, что кнопки раскрытия подробностей all будут перемещаться вправо при запуске поиск, а затем все снова возвращаются после завершения поиска.
Я сам достиг этого в вашем примере, вызвав reloadData
в вашем основном представлении таблицы в двух методах UISearchDisplayDelegate
, которые я добавил в ваш код:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller
{
[[[self mainTableController] tableView] reloadData];
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller
{
[[[self mainTableController] tableView] reloadData];
}
Это заставит ваши представления раскрытия подробностей быть перемещенными, чтобы учесть видимость индекса таблицы, сохраняя положение всех индикаторов раскрытия, согласованных друг с другом, в режиме поиска или нет.
Обновление
Я играл с перезагрузкой табличного представления в других методах UISearchDisplayDelegate
, включая:
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
- (void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView
Но они создают довольно резкий эффект, когда позиции кнопок раскрытия подробностей резко скатываются, поэтому я рекомендую методы willBeginSearch
и willEndSearch
, как указано ранее.
Ответ 2
Самый простой и, возможно, самый чистый способ, который я могу придумать, - сообщить вашему диспетчеру просмотра (или представлению) прослушивание событий клавиатуры. Затем, когда клавиатура сведена к минимуму, вы уходите с первого ответчика на панель поиска и перезагружаете таблицу (если она не перезагружает ее должным образом).
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//Your code here
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:self.window];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:self.window];
}
return self;
}
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name: UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name: UIKeyboardWillHideNotification object:nil];
}
Затем добавьте эти две функции и сделайте то, что вам нужно.
- (void)keyboardWillHide:(NSNotification *)aNotification
{
//searchbar resignFirstResponder
//Tableview reload (if needed)
}
- (void)keyboardWillShow:(NSNotification *)aNotification
{
//Don't really need this one for your needs
}
Поскольку вы отменяете первого ответчика в функции keyboardwillhide (до того, как клавиатура начинает двигаться), ваши ячейки таблицы должны перезагружаться должным образом, не перезагружая их снова.
Ответ 3
Проблема не ограничивается таблицами с заголовками индексов раздела. У меня была аналогичная проблема с заголовками заголовков разделов. Если вы добавите
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (tableView != [[self searchDisplay] searchResultsTableView]) {
return [NSString stringWithFormat:@"Section %c", 'A' + section];
} else {
return nil;
}
}
в программу "Минимальный исполняемый пример", то вы увидите, что заголовки заголовков разделов также отображаются в представлении таблицы поиска, как только перезагрузка основного табличного представления. (О той же проблеме сообщалось здесь: Удаление заголовков заголовков из UITableView в режиме поиска.)
Единственное решение, о котором я знаю, заключается в том, чтобы избежать всех обновлений в представлении основной таблицы до тех пор, пока активен контроллер отображения поиска ([self.searchDisplay isActive] == YES
) и перезагружает представление главной таблицы только при выгрузке таблицы поиска:
- (void)searchDisplayController:(UISearchDisplayController *)controller willUnloadSearchResultsTableView:(UITableView *)tableView {
[[[self mainTableController] tableView] reloadData];
}