Я пытаюсь использовать UISplitViewController, где вторичный контроллер должен предоставлять функцию «закрытия» (с помощью кнопки или элемента панели кнопок) всякий раз, когда UISplitViewController находится в параллельном режиме, но должен скрывать функцию в другое время. Я попытался поместить это в контроллер вторичного представления:
override func viewWillAppear(_ animated: Bool) {
if splitViewController!.primaryHidden {
// hide the "close" UI artifact
} else {
// show the "close" UI artifact
}
}
Это правильно устанавливает видимость функции «закрыть» при первом отображении вторичного представления, но если UISplitViewController переключается между развернутым и свернутым (скажем, путем поворота iPhone 6s Plus), то эта функция больше не вызывается (что имеет смысл , поскольку вторичный контроллер остается видимым). Следовательно, функция «close» остается в своем исходном состоянии - скрыта или отображается - даже когда UISplitViewController меняет режим.
Как я могу заставить функцию «закрыть» скрыть или показать в ответ на изменения в режиме UISplitViewController?





Хорошо, я нашел простое решение. Я совершал ошибку новичка. Уловка состоит в том, чтобы переопределить viewWillLayoutSubviews() вместо viewWillAppear(animated:). Дальше все работает как хочу. Кажется, что viewWillLayoutSubviews() вызывается (иногда более одного раза) каждый раз, когда содержащий UISplitViewController меняет режим отображения, и это именно то, на что мне нужно ответить. Единственная проблема заключается в том, что splitViewController может быть nil для некоторых из этих вызовов, поэтому его нужно реализовать следующим образом:
override func viewWillAppear(_ animated: Bool) {
if let svc = splitViewController {
if svc.primaryHidden {
// hide the "close" UI artifact
} else {
// show the "close" UI artifact
}
}
}
Пытаясь найти решение, я попытался переопределить traitCollectionDidChange(previousTraitCollection:). (Я пробовал это, потому что хотел реагировать на поворот устройства.) Сначала я подумал, что наткнулся на что-то, потому что эта функция также вызывается всякий раз, когда устройство вращается. Интересно (и досадно) я обнаружил, что свойство splitViewController моего представления было nil при вызове этой функции. Кажется странным, что это должно быть так, поскольку ни viewDidDisappear(animated:), ни viewWillAppear(animated:) не вызываются, когда UISplitViewController реконфигурирует себя. Но почему это должен быть nil - это, наверное, вопрос другого дня.
Для этого есть уведомление UIViewControllerShowDetailTargetDidChangeNotification:
// Sometimes view controllers that are using showViewController:sender and
// showDetailViewController:sender: will need to know when the split view
// controller environment above it has changed. This notification will be
// posted when that happens (for example, when a split view controller is
// collapsing or expanding). The NSNotification's object will be the view
// controller that caused the change.
UIKIT_EXTERN NSNotificationName const UIViewControllerShowDetailTargetDidChangeNotification NS_AVAILABLE_IOS(8_0);
Используйте следующим образом
- (void)viewDidLoad{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showDetailTargetDidChange:) name:UIViewControllerShowDetailTargetDidChangeNotification object:self.splitViewController];
}
- (void)showDetailTargetDidChange:(NSNotification *)notification{
// changed from collapsed to expanded or vice versa
}
Этот пример Apple демонстрирует, как аксессуар ячейки таблицы изменяется с индикатора раскрытия в портретной ориентации (обозначающего, что произойдет нажатие) на его удаление при переходе в режим разбиения на альбомную ориентацию: https://developer.apple.com/library/archive/samplecode/AdaptivePhotos/Introduction/Intro.html
Обратите внимание на бета-версию iOS 13: используйте addObserver с объектом nil, потому что в настоящее время есть ошибка, когда они отправляют уведомление с использованием неправильного объекта. Они используют свой новый UISplitViewControllerPanelImpl из внутреннего кластера классов вместо объекта UISplitViewController.http://www.openradar.appspot.com/radar?id=4956722791710720
UIViewControllerShowDetailTargetDidChangeNotification никогда не называется. Есть идеи, почему?
Если используется бета-версия iOS13, измените addObserver на использование объекта nil. В настоящее время они используют неправильный объект для фильтрации уведомления, но я отправил отзыв, чтобы исправить это.
Спасибо за ответ @malhal. Я вижу эту проблему и в iOS 12.4. Я пробовал передавать как nil, так и splitvc NotificationCenter.default.addObserver(self, selector: #selector(handleSplitVCTransition), name: UIViewController.showDetailTargetDidChangeNotification, object: nil). Но оба никогда не стреляли
Попробуйте образец Apple, который я только что добавил к ответу, и проверьте, появляется ли уведомление. Мне нравится использовать симулятор iPhone 8 Plus для тестирования.
Спасибо. Я постараюсь посмотреть
Для справки в будущем:
А как насчет использования UISplitViewControllerDelegate ??
У него есть метод, называемый
splitViewController:willChangeToDisplayMode:
это должно делать именно то, что вы ищете.
Можете выложить фото проблемы. Я использую в своем приложении 4 SplitViewController, и они были головной болью, чтобы начать работать. Я постараюсь помочь, если смогу, но мне будет легче разобраться с некоторыми фотографиями проблемы и тем, как вы хотите, чтобы она выглядела