UISearchBar не будет отвечать в UISplitviewController Master
У меня довольно стандартная настройка UITableview
в качестве главного контроллера в UISplitviewController
, универсальном iOS9
приложении.
Опять же, стандартный тариф, я вставил UISearchBar
в качестве заголовка таблицы.
self.searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
self.searchController.searchResultsUpdater = self;
self.searchController.dimsBackgroundDuringPresentation = NO;
self.searchController.hidesNavigationBarDuringPresentation = NO;
[self.searchController.searchBar sizeToFit];
self.tableView.tableHeaderView = self.searchController.searchBar;
self.definesPresentationContext = YES;
Не нужно показывать остальную часть моего кода, искать и все работать как ожидалось, на iPhone
. Моя проблема в том, что панель поиска никогда не получает фокуса или присутствует клавиатура при запуске на iPad
. Никакой ответ, кажется, не получает прикосновений. Даже не реагирует на программную попытку becomeFirstResponder
.
Ничего не происходит.
Панель поиска видна и размещена соответствующим образом, нет проблем с подслоем или наложением.
Он отлично работает на iPhone
. Получает касание, представляет клавиатуру, выполняет поиск. Предположительно, существует критическая разница в представлении, когда UISplitviewController
рушится. С часами поиска, пролистывая документацию и каждый обучаемый, с которым я сталкиваюсь, я не нашел подобного опыта, который удивляет.
Дополнительное примечание. Если я использую многозадачность для сокращения раздвоенного вида, чтобы свернуть на iPad, панель поиска работает так же, как и на iPhone
. Это определенно связано с сложенным состоянием вида split.
ОБНОВЛЕНИЕ: (ближе)
После дальнейших экспериментов я обнаружил, что панель поиска работает на iPad, если вы запускаете приложение в ландшафте. В портретном режиме мой основной контроллер скрыт. Он перемещается по выбору displayModeButtonItem
, который установлен в leftBarButtonItem
подробного контроллера. То есть, когда searchBar ломается и больше не будет реагировать на касания.
Если я начну с пейзажа, затем поверните на портрет, он перестанет работать. Вращение назад к пейзажу не исправляет его. После разрыва он остается сломанным до перезапуска.
Я попытался переместить definesPresentationContext
в метод viewWillAppear
главного контроллера, но это не повлияло.
Дальнейшее обновление:
Еще одно неожиданное обстоятельство заключается в том, что никаких проблем с панелью поиска вообще нет на iPhone 6plus. Работает независимо от ориентации, рушится или нет и не имеет значения, в каком состоянии она начинается. Я ожидаю, что это будет так же, как iPad, когда в альбомной ориентации. Полностью работает на iPhone
.
Я до сих пор не понял этого. Моя последняя попытка исправить, я переместил всю инициализацию контроллера поиска в метод viewDidLayoutSubviews
. Никаких изменений.
Кроме того, я заметил, что когда поиск активен, экранная клавиатура, если я поворачиваю iPad, клавиатура уходит, но панель поиска остается активной. Сначала я не понял, потом увидел, что кнопка отмены все еще отображается. Он не получит прикосновений и не имеет клавиатуры, но, по-видимому, это все еще первый ответчик.
Пример проекта, загруженного в GitHub:
Репозиторий Github
ПРИМЕЧАНИЕ. Не было проблем, пока я не добавил в проект мои методы UISplitview Delegate. Я хотел бы сразу добавить это к моему вопросу, поэтому я даже не пытался понять, как эти методы делегирования влияют на панель поиска, но, очевидно, проблема там создается где-то.
Обновление:
Я попробовал еще несколько вариантов без успеха.
- Переместить панель поиска в заголовок раздела. Нет радости.
- Поместите панель поиска в UIView в виде содержимого. Нет радости.
- Удалить панель поиска при исчезновении, снова включить. Нет радости.
- Манипулируйте размер рамки панели поиска, чтобы убедиться, что она не обрезана. Нет радости.
Я также посмотрел на иерархию представлений в профилировщике, панель поиска - верхний уровень, не покрытый чем-либо еще.
Заключительная обертка:
@tomSwift обходное решение действительно исправило мою проблему на iPad. При дальнейшем тестировании я обнаружил, что он нарушил мой интерфейс iPhone. Предположительно, это больше проблема с моей собственной настройкой и временем создания контроллеров Master/Detail View. Казалось бы, некоторые важные объекты больше не были созданы вовремя, поскольку, возможно, контроллер подробного представления еще не существовал. Я ткнул, чтобы исправить, переместив критические элементы в App Delegate, но это стало громоздким, и я не мог его легко сузить, поэтому я взломал исправление с помощью
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
}
Более элегантное решение, скорее всего, будет, но это заняло достаточно моего времени. Сейчас все работает. Радиолокационная заявка-28304096
Ответы
Ответ 1
Это явно ошибка в UISplitViewController
и/или UISearchController
. Конечно, подайте радар с Apple и прикрепите образец кода.
Я думаю, что ошибка включает UISplitViewController.displayMode UISplitViewControllerDisplayModeAutomatic
. Когда я меняю preferredDisplayMode
на UISplitViewControllerDisplayModeAllVisible
, тогда все начинает работать:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
navigationController.topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem;
splitViewController.delegate = self;
splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
return YES;
}
Главное, что это изменение - это макет по умолчанию для портрета на iPad, который, как я понимаю, может быть не идеальным. Я также играл с настройкой preferredDisplayMode
на UISplitViewControllerDisplayModeAllVisible
, а затем вернул его к UISplitViewControllerDisplayModeAutomatic
; это отлично работало до тех пор, пока экранная ориентация не изменилась - тогда все это снова сломалось. Возможно, вам удастся пойти дальше по этому пути.
Я также сделал следующее дополнение в AppDelegate
, чтобы заставить контроллер поиска деактивироваться при изменении displayMode
. (Я также должен был публиковать свойство searchController
публично в MasterViewController).
- (void)splitViewController:(UISplitViewController *)svc willChangeToDisplayMode:(UISplitViewControllerDisplayMode)displayMode {
UINavigationController *navigationController = [svc.viewControllers firstObject];
MasterViewController* mvc = (MasterViewController*) navigationController.topViewController;
[mvc.searchController setActive: NO];
}
Ответ 2
Играя с вашим проектом и обнаружив, что проблема заключается в том, что ваш поисковый контроллер никогда не настроен на активный. Поэтому я подклассифицировал UISplitViewController и сделал его делегатом для себя, чтобы он мог уведомлять контроллеры дочерних представлений при изменении режима, чтобы вы могли настроить его в нужное время.
Используйте этот метод делегата для создания уведомления:
- (void)splitViewController:(UISplitViewController *)svc willChangeToDisplayMode:(UISplitViewControllerDisplayMode)displayMode {
NSLog(@"WILL CHANGE TO DISPLAY MODE: %ld", (long)displayMode);
NSNumber *displayNumber = [NSNumber numberWithInteger:displayMode];
NSDictionary *userInfo = @{ @"displayMode": displayNumber };
NSNotification *modeChangedNotif = [NSNotification notificationWithName:@"modeChanged" object:nil userInfo:userInfo];
[[NSNotificationCenter defaultCenter] postNotification:modeChangedNotif];
}
Затем в вашем MasterViewController вы можете сделать это в viewDidLoad
:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(modeChanged) name:@"modeChanged" object:nil];
В этом методе вы можете сделать чек для определенного перечисления displayMode, но ради получения его работы я просто сделал:
- (void) modeChanged {
[self.searchController setActive:YES];
}